SQL中的国家邻接建模
我试图在MySQL中模拟哪些国家彼此接壤。我有三张桌子:SQL中的国家邻接建模,sql,mysql,graph,Sql,Mysql,Graph,我试图在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
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(出现在所有三个表中)和国家/地区)
克罗地亚与所有其他国家接壤,这在node_邻接表中表示为:
59 86
86 130
86 178
86 227
86 232
因此,塞尔维亚的ID可能显示为节点ID\u 1
或节点ID\u 2
。此表中的数据基本上是无向图数据
问题:
如果名称为“克罗地亚”,我应该使用什么SQL来检索它的邻居
Bosnia and Herzegovina
Hungary
Montenegro
Serbia
Slovenia
将邻接信息存储为有向图数据会提高检索效率吗?例如,克罗地亚与匈牙利接壤,匈牙利与克罗地亚接壤,基本上重复了关系的存储:
86 130
130 86
我将存储这两个关系(匈牙利与克罗地亚接壤,克罗地亚与匈牙利接壤),这样您就只需要查询一列
SELECT c.country FROM countries AS c
INNER JOIN node_adjacency AS n
ON n.node_id_1 = c.countryID
WHERE c.countryID = 86
如果您要复制关系(即A国与B国共享边界,B国与A国共享边界),您可以通过简单的选择找到一种方法。如果每对国家/地区只存储一个关系,则需要在node_邻接表中按两列进行搜索(运行两个select语句并执行并集)。要同时执行两列,只需将两个查询并集(借用Matthew Jones):
如果这样做,您将复制查询而不是数据(使用的空间减少50%),而且仍然非常简单。这只是我的想法,所以我不知道这是否是最有效的解决方案,可能需要进行调整,但我认为它应该可以工作:
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'
选择
边境
从…起
C类国家
左外连接节点_邻接NA1 ON
NA1.node_id_1=C.country_id或
NA1.node_id_2=C.country_id
以内陆国家为边界
(
BORDER.country\u id=NA1.node\u id\u 1或
BORDER.country\u id=NA1.node\u id\u 2
)及
BORDER.country\u id C.country\u id
哪里
C.国家=‘克罗地亚’
因为你的图不是有向图,我认为把它存储为有向图是没有意义的。您可能还想在Google上搜索“Celko SQL Graph”,因为他在SQL中的树、图和层次结构方面做了大量的高级工作,并且有一本专门介绍此主题的优秀书籍。您可以创建联合视图以避免重复:
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'
我已经走了这么远,但如果我只有“克罗地亚”这个词,而不是86,它还能做到吗?是的;只需更改WHERE子句。已经有了用于Smarties、Tree和Hierarchies的SQL,但不幸的是,Celko的许多写作超出了我的理解。谢谢你的解决方案!
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'