我正在尝试模拟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_1
或node_id_2
。该表中的数据基本上是非有向图数据。
问题:
鉴于名称'Croatia',我应该用什么SQL来检索它的邻居?
Bosnia and Herzegovina
Hungary
Montenegro
Serbia
Slovenia
将邻接信息存储为有向图数据会有任何检索效率提升吗?例如。克罗地亚与匈牙利接壤,匈牙利与克罗地亚接壤,基本上重复了对这种关系的存储:
86 130
130 86
答案 0 :(得分: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中对树,图和层次结构做了大量的高级工作,并且有一本很好的专门讨论这个主题的书。
答案 1 :(得分: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
答案 2 :(得分:2)
要做两个列,只需将两个查询合并在一起(借用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%的空间),它仍然非常简单。
答案 3 :(得分:1)
如果您正在重复关系(即国家A与B边界,B与A边界),您可以通过简单的选择获得一种方式。如果每对国家只存储一个关系,则需要在node_adjacency表中的两列中搜索(运行两个select语句并执行联合)。
答案 4 :(得分: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'