2009-11-11 20 views
0

我想模擬哪些國家在MySQL中彼此相鄰。我有三個表:在SQL中建模國家鄰接關係

nodes 
----- 
node_id MEDIUMINT 

countries 
--------- 
country_id MEDIUMINT (used as a foreign key for nodes.node_id) 
country CHAR(64) 
iso_code CHAR(2) 

node_adjacency 
-------------- 
node_id_1 MEDIUMINT (used as a foreign key for nodes.node_id) 
node_id_2 MEDIUMINT (used as a foreign key for nodes.node_id) 

我欣賞的節點表是在這個例子中多餘的,但是這是一個更大的架構,節點可以代表許多其他項目以外的其他國家的一部分。

這裏的一些數據(IDS(這出現在所有三個表中)和國家)

59 Bosnia and Herzegovina 
86 Croatia 
130 Hungary 
178 Montenegro 
227 Serbia 
232 Slovenia 

克羅地亞被所有其他國家接壤,這是在node_adjacency表表示爲:

59 86 
86 130 
86 178 
86 227 
86 232 

因此塞爾維亞的身份證可能會顯示爲node_id_1node_id_2。該表中的數據基本上是非有向圖數據。

問題:

定名爲「克羅地亞」,哪些SQL我應該使用檢索它的鄰居?

Bosnia and Herzegovina 
Hungary 
Montenegro 
Serbia 
Slovenia 

將鄰接信息存儲爲有向圖數據會有任何檢索效率增益嗎?例如。克羅地亞接壤匈牙利,匈牙利和克羅地亞接壤,基本上是複製關係的存儲:

86 130 
130 86 

回答

3

這只是從我的頭頂,所以我不知道這是否是最高效的解決方案,它可能需要一個調整,但我認爲它應該工作:

SELECT 
    BORDER.country 
FROM 
    Countries AS C 
LEFT OUTER JOIN Node_Adjacency NA1 ON 
    NA1.node_id_1 = C.country_id OR 
    NA1.node_id_2 = C.country_id 
INNER JOIN Countries AS BORDER ON 
    (
    BORDER.country_id = NA1.node_id_1 OR 
    BORDER.country_id = NA1.node_id_2 
    ) AND 
    BORDER.country_id <> C.country_id 
WHERE 
    C.country = 'CROATIA'   

由於您的圖表沒有定向,我認爲將它作爲有向圖存儲是沒有意義的。您可能還想要谷歌的「Celko SQL Graph」,因爲他已經在SQL中的樹,圖表和層次結構方面做了大量的高級工作,並且有一本關於該主題的優秀書籍。

+0

已經得到了Smarties和Trees和Hierarchies的SQL,但不幸的是,很多Celko的寫作都在我的頭上。感謝您的解決方案! – jetboy 2009-11-11 23:31:28

2

我會同時存儲關係(匈牙利接壤的克羅地亞,克羅地亞接壤匈牙利),這樣你永遠只需要查詢一列。

SELECT c.country FROM countries AS c 
INNER JOIN node_adjacency AS n 
ON n.node_id_1 = c.countryID 
WHERE c.countryID = 86 
1

如果您正在複製的關係(即國內A股邊境B和B股邊境A)你可以用一個簡單的選擇方式。如果每個國家/地區只存儲一個關係,則需要通過node_adjacency表中的兩列進行搜索(運行兩條select語句並執行聯合)。

2

要做到兩列,只是工會兩個查詢一起(借款由馬修·瓊斯):

SELECT c.country FROM countries AS c 
INNER JOIN node_adjacency AS n 
ON n.node_id_1 = c.countryID 
WHERE c.countryID = 86 
UNION 
SELECT c.country FROM countries AS c 
INNER JOIN node_adjacency AS n 
ON n.node_id_2 = c.countryID 
WHERE c.countryID = 86 

如果你做這種方式,可以複製的,而不是你的數據(少用50%的空間)查詢,它仍然非常簡單。

+0

我走到這一步,但如果我只用了一句話「克羅地亞」和不是86,它還能完成嗎? – jetboy 2009-11-11 22:58:44

+0

是的;只需更改WHERE子句。 – 2012-06-19 13:13:35

1

您可以創建一個聯合視圖,以避免重複:

CREATE VIEW adjacency_view (node_id_1, node_id_2) 
AS 
SELECT node_id_1, node_id_2 FROM node_adjacency 
UNION ALL 
SELECT node_id_2, node_id_1 FROM node_adjacency 

所以,你的查詢變得相當簡單:

SELECT c1.country 
FROM adjacency_view 
INNER JOIN countries AS c1 on c1.country_id = adjacency_view.node_id_1 
INNER JOIN countries AS c2 on c2.country_id = adjacency_view.node_id_2 
WHERE c2.country = 'CROATIA'