提前感谢您的时间
我有mondial数据库中的下表(Website,Documentation)。
CREATE TABLE borders
(Country1 VARCHAR(4),
Country2 VARCHAR(4),
Length FLOAT,
CONSTRAINT CHECK (Length > 0),
CONSTRAINT BorderKey PRIMARY KEY (Country1,Country2));
该表格不包含互惠值(它只包含 Country1,Country2 或 Country2,Country1 以定义边框)
我需要提出一个查询,输出所有不是邻居但是邻居邻居的国家夫妇(所有被其他国家分开的国家夫妇)。
Country1和Country2包含国家代码,如" F"对于法国,"我"意大利等等。以下是输出的示例行:
RSM || ˚F
RSM是圣马力诺共和国的代码(圣马力诺是一个完全被意大利包围的飞地)。 RSM显然不是法国的邻居,但意大利是,因此输出包含 RSM,F 这对夫妇,并且它还包含所有其他邻国的类似夫妇到意大利。
我花了几个小时试图找出解决方案,但我还没有达成解决方案,而且我已经有很多问题,这就是我所做的:
我首先进行查询,找出某个国家/地区的所有邻居。
SELECT Country1
FROM borders
WHERE Country2 = "RSM"
UNION
SELECT Country2
FROM borders
WHERE Country1 = "RSM"
这显然只会输出"我"这是意大利的代码(所以它是正确的)。我已经有一个问题:有更好的方法可以做到这一点还是可以的?
然后我把它带到下一步并进行查询以找到之前找到的邻居的所有邻居:
SELECT Country1
FROM borders
WHERE Country2 IN (
SELECT Country1
FROM borders
WHERE Country2 = "RSM"
UNION
SELECT Country2
FROM borders
WHERE Country1 = "RSM"
)
UNION
SELECT Country2
FROM borders
WHERE Country1 IN (
SELECT Country1
FROM borders
WHERE Country2 = "RSM"
UNION
SELECT Country2
FROM borders
WHERE Country1 = "RSM"
)
所以我基本上做同样的事情,但不是寻找特定国家的邻居,而是搜索某一组国家的所有邻居。查询未完成,因为我需要从输出中删除起始国家及其所有邻居,以便查询变为:
SELECT "RSM", Country1
FROM (
SELECT Country1
FROM borders
WHERE Country2 IN (
SELECT Country1
FROM borders
WHERE Country2 = "RSM"
UNION
SELECT Country2
FROM borders
WHERE Country1 = "RSM"
)
UNION
SELECT Country2
FROM borders
WHERE Country1 IN (
SELECT Country1
FROM borders
WHERE Country2 = "RSM"
UNION
SELECT Country2
FROM borders
WHERE Country1 = "RSM"
)
) tmp
WHERE tmp.Country1 NOT IN (
SELECT Country1
FROM borders
WHERE Country2 = "RSM"
UNION
SELECT Country2
FROM borders
WHERE Country1 = "RSM"
) AND tmp.Country1 != "RSM"
此查询适用于单个起始国家/地区(RSM),但我需要输出所有不同的内容(如果 RSM,F ,则表示输出中没有 F,RSM 对。如上所述,我也认为我开发的查询非常糟糕,因为它一遍又一遍地重复相同的查询。我已经搜索过避免这种情况的方法,我找到了有趣的解决方案,例如 WITH tmp AS查询子句,但我使用MySQL 和 WITH AS 子句不受支持。
那么你的专家怎么想?这至少接近正确的方式吗?我错过了一些明显的东西吗?
提前感谢您的时间,如果这个可怕的疑问让您头疼,我会感到抱歉。
编辑1:我创建了一个包含表格,数据和查询的SQL Fiddle,以防您想要轻松运行查询。我希望它会对某人有所帮助。
答案 0 :(得分:1)
假设数据具有倒数值,意味着('France','Italy')和('Italy','France')都在数据中,那么您基本上可以通过连接和过滤来实现:< / p>
select b1.country1, b2.country2
from borders b1 join
borders b2
on b1.country2 = b2.country1
where not exists (select 1
from borders b
where b.country1 = b1.country1 and b.country2 = b2.country2
);
编辑:没有倒数值,我只想创建一个视图并使用查询视图:
create view v_borders as
select country1, country2 from borders union all
select country2, country1 from borders;
然后使用查询中的视图。你也可以在查询中做到这一点,它只是凌乱,因为MySQL不支持公用表表达式(CTE)。
答案 1 :(得分:1)
用户jpw在评论中解决了问题。
许多用户建议查看表格,以使夫妻或国家像这样对称:
CREATE VIEW borders_symmetrical AS
SELECT Country1, Country2 FROM borders
UNION ALL
SELECT Country2, Country1 FROM borders;
在我看来,这确实是一个很好的建议,它显示了视图如何真正有用。现在,查询变得更加容易:
SELECT DISTINCT b1.Country1, b2.Country2
FROM borders_symmetrical b2
JOIN borders_symmetrical b1
ON b2.Country1 = b1.Country2
WHERE b2.Country2 <> b1.Country1
#AND (b1.Country1 = 'RSM' OR b2.Country2 = 'RSM') # Debug a single nation
AND b2.country2 NOT IN (
SELECT Country2
FROM borders_symmetrical
WHERE Country1 = b1.Country1
) AND b1.Country1 < b2.Country2
我转发了这个,因为jpw没有提交和回答,只是对帖子发表了评论。
再次感谢大家的宝贵时间,你们给了我很多帮助,让我了解了几个关于SQL和数据库的重要事项。
答案 2 :(得分:0)
这是我能想到的最短的,无需修改您选择的数据库:
SELECT DISTINCT reciprocalBorders1.first, reciprocalBorders2.second, reciprocalBorders1.second
FROM (SELECT Country1 first, Country2 second FROM borders UNION
SELECT Country2 first, Country1 second FROM borders) reciprocalBorders1,
(SELECT Country1 first, Country2 second FROM borders UNION
SELECT Country2 first, Country1 second FROM borders) reciprocalBorders2
WHERE reciprocalBorders1.second = reciprocalBorders2.first
AND reciprocalBorders1.first < reciprocalBorders2.first
AND reciprocalBorders1.first <> reciprocalBorders2.second
AND NOT EXISTS(
SELECT 1
FROM (SELECT Country1 first, Country2 second FROM borders UNION
SELECT Country2 first, Country1 second FROM borders) reciprocalBorders3
WHERE reciprocalBorders3.first = reciprocalBorders1.first
AND reciprocalBorders3.second = reciprocalBorders2.second
)
ORDER BY 1, 2, 3;
第三列包含分隔第一列和第二列中国家/地区的国家/地区。
显然,使用视图可以缩短FROM
部分。每个FROM部分都将反转表添加到自身,以便使A | F&#39;和&#39; F | A&#39;一个表中的条目。
关于WHERE
部分:
SELECT DISTINCT
确保您不会获得A和B国家的双重结果,这两个国家/地区与两个或更多相同国家/地区共享边界,例如:奥地利与瑞士和德国相连,两者都与法国接壤,但你不想要两个奥地利,法国的参赛作品