簡體   English   中英

在SQL中建模國家/地區鄰接關系

[英]Modelling country adjacency in SQL

我正在嘗試建模哪些國家在MySQL中彼此毗鄰。 我有三個表:

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)

我知道在此示例中,節點表是多余的,但這是更大的體系結構的一部分,在該體系結構中,節點可以代表國家以外的許多其他項目。

以下是一些數據(ID(在所有三個表格中都出現)和國家/地區)

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

因此,塞爾維亞的ID可能顯示為node_id_1node_id_2 該表中的數據本質上是無向圖數據。

問題:

給定名稱“克羅地亞”,我應該使用什么SQL來檢索其鄰居?

Bosnia and Herzegovina
Hungary
Montenegro
Serbia
Slovenia

將鄰接信息存儲為有向圖數據時,檢索效率會有所提高嗎? 例如,克羅地亞與匈牙利接壤,匈牙利與克羅地亞接壤,從本質上來說,這種關系的存儲是重復的:

86  130
130 86

這只是我的頭上的問題,所以我不知道這是否是性能最高的解決方案,它可能需要調整,但我認為它應該可以工作:

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'        

由於您的圖不是有向圖,因此我認為將其存儲為有向圖是沒有道理的。 您可能還需要Google“ Celko SQL Graph”,因為他在SQL的樹,圖和層次結構方面做了大量的高級工作,並且有一本專門介紹該主題的優秀書籍。

我將存儲兩個關系(匈牙利與克羅地亞接壤,克羅地亞與匈牙利接壤),因此您只需要查詢一列。

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

要完成這兩個列,只需將兩個查詢合並在一起(從Matthew Jones借用):

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%的空間),而且它仍然非常簡單。

如果您正在復制關系(例如,國家A與B接壤,B與A接壤),則可以通過簡單的選擇找到一種方法。 如果每對國家/地區僅存儲一個關系,則需要按node_adjacency表中的兩列進行搜索(運行兩個select語句並執行一個並集)。

您可以創建聯合視圖以避免重復:

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'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM