繁体   English   中英

SQL 根据另一个表中的两列有效地从一个表中选择不同的行

[英]SQL efficiently select distinct rows from one table depending on two columns from another table

我的 Postgres 数据库中有两个表, nodesegdes 我正在尝试查找任意节点 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_idtarget_id充当引用nodes的外键。

直接邻居被定义为 id 至少出现一次的节点,在edges表中,或者在source_idtarget_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM