【问题标题】:SQL get ALL rows which share foreign keysSQL获取共享外键的所有行
【发布时间】:2020-01-13 11:14:00
【问题描述】:

我希望找到所有至少有一个具有某些(非特定)外键的兄弟的行。

mytable
id |fk_id    
---|--------
1  |100 
2  |200
3  |200
4  |300 
5  |300
6  |300

我的查询应该返回第 2 到第 6 行,但不是第 1 行,因为它是单独的。

我想出了一个可行的解决方案,它使用了 2 个子查询,这似乎太多了。 (在 20k+ 行上运行几秒钟,这意味着至少 O(n^2)

SELECT * from mytable 
WHERE fk_id IN 
  (SELECT fk_id FROM
    (SELECT fk_id, SUM(fk_id) as mycnt from mytable GROUP BY fk_id)
  WHERE mycnt >= 2)

什么是更快的解决方案?

常规编程非 SQL 解决方案是仅按 fk_id 排序,然后摆脱单项,这对于通用排序来说是 O(nlogn) 加上 O(n) 只是迭代一次,所以 O(nlogn)

使用 SQLite,但其他 SQL 方言也可以。

【问题讨论】:

    标签: sql sqlite group-by


    【解决方案1】:

    存在:

    SELECT m.* FROM mytable m
    WHERE EXISTS (
      SELECT 1 FROM mytable
      WHERE id <> m.id AND fk_id = m.fk_id
    )
    

    请参阅demo
    或者使用 COUNT() 窗口函数:

    SELECT m.id, m.fk_id 
    FROM (
      SELECT *, COUNT(id) OVER (PARTITION BY fk_id) counter  
      FROM mytable
    ) m
    WHERE m.counter > 1
    

    请参阅demo
    结果:

    | id  | fk_id |
    | --- | ----- |
    | 2   | 200   |
    | 3   | 200   |
    | 4   | 300   |
    | 5   | 300   |
    | 6   | 300   |
    

    【讨论】:

    • 谢谢!很高兴知道不同的选择:)
    • 我对 EXISTS 版本的运行速度感到惊讶,可能是因为我为外键添加了索引。
    【解决方案2】:

    这样的事情应该可以工作:

    select * 
    from mytable
    where fk_id in (
      select fk_id
      from mytable
      group by fk_id
      having count(*) > 1
    )
    

    使用inner join的另一种选择:

    select * 
    from mytable m
    inner join
    (
      select fk_id
      from mytable
      group by fk_id
      having count(*) > 1
    ) fks on fks.fk_id = m.fk_id
    

    【讨论】:

    • 谢谢!那确实更快:)
    • @Sint 确实更快 只有源表足够紧凑,否则 WHERE EXISTS 可能会更快。
    猜你喜欢
    • 2017-02-10
    • 1970-01-01
    • 2021-01-13
    • 2012-11-18
    • 2023-03-06
    • 2021-10-09
    • 1970-01-01
    • 2015-08-28
    • 1970-01-01
    相关资源
    最近更新 更多