![](/img/trans.png)
[英]SQL How to construct a query that two columns from one table depending on another table?
[英]SQL efficiently select distinct rows from one table depending on two columns from another table
我的 Postgres 数据库中有两个表, nodes
和egdes
。 我正在尝试查找任意节点 ID 子集的直接邻居。
这是我的架构:
CREATE TABLE nodes (
id INT,
prop_1 VARCHAR(64),
prop_2 VARCHAR(64)
);
CREATE TABLE edges (
source_id INT,
target_id INT
);
使用一些示例数据:
INSERT INTO nodes (id, prop_1, prop_2) VALUES
(1, 'lorem', 'ipsum'),
(2, 'dolor', 'sit'),
(3, 'conseteteur', 'sadipiscing'),
(4, 'elitr', 'sed'),
(5, 'diam', 'nonumy');
INSERT INTO edges (source_id, target_id) VALUES
(1, 2),
(1, 3),
(1, 4),
(3, 4),
(2, 4),
(4, 5);
其中source_id
和target_id
充当引用nodes
的外键。
直接邻居被定义为 id 至少出现一次的节点,在edges
表中,或者在source_id
或target_id
列下,并且与我的任意 id 之一在同一行。
我想我已经让它几乎可以工作了,但是我的查询返回重复,而且很可能效率低下。 这是具有上述模式的 SQL Fiddle ,我试图使用以下查询为 id 为 1 和 5 的节点找到不同的直接邻居:
WITH sources(id) AS (
SELECT target_id FROM edges WHERE edges.source_id IN (1, 5)
), targets(id) AS (
SELECT source_id FROM edges WHERE edges.target_id IN (1, 5)
) SELECT DISTINCT * FROM nodes, sources, targets WHERE nodes.id = sources.id OR nodes.id = targets.id
我希望我的查询从nodes
返回以下行:
ID | 道具_1 | 道具_2 |
---|---|---|
2 | 忧郁 | 坐 |
3 | 信奉者 | 悲伤的 |
4 | 删除 | sed |
从小提琴中可以看出,我似乎得到了正确的结果,但它们同时包含重复和多余的列。
如何从nodes
只返回正确的行? 我的方法是不是特别低效?
如果您仅从nodes
选择,您的查询将返回正确的结果:
SELECT DISTINCT nodes.*
FROM ...
但是,我建议将表格正确连接:
SELECT DISTINCT n.*
FROM nodes n INNER JOIN edges e
ON n.id = CASE WHEN e.source_id IN (1, 5) THEN e.target_id ELSE e.source_id END
WHERE e.source_id IN (1, 5) OR e.target_id IN (1, 5)
ORDER BY n.id;
或EXISTS
:
SELECT n.*
FROM nodes n
WHERE EXISTS (
SELECT *
FROM edges e
WHERE (e.source_id IN (1, 5) OR e.target_id IN (1, 5))
AND n.id = CASE WHEN e.source_id IN (1, 5) THEN e.target_id ELSE e.source_id END
)
ORDER BY n.id;
请参阅演示。
一个简单的 UNION 可以消除重复项,因为默认行为是 UNION DISTINCT。
但是,当然,单独的 IN 子句也可以这样做,因为 IN 子句列表中包含多少个值的实例并不重要,每个外部节点行最多可以在结果中出现一次。
SELECT n.*
FROM nodes AS n
WHERE id IN (
SELECT target_id FROM edges WHERE edges.source_id IN (1, 5)
UNION
SELECT source_id FROM edges WHERE edges.target_id IN (1, 5)
)
;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.