【问题标题】:Get rows from two tables with multiple matches in the other从两个表中获取具有多个匹配项的行
【发布时间】:2021-11-22 17:04:35
【问题描述】:

我有两个所有相似的字段表:

table_1: 
field_1, field_2, field_3, field_4
 

table_2: 
field_1, field_2, field_3, field_4

这里field_1可以作为外键连接两个表。

我想从table_1table_2 中获取在table_1 中至少有一行但在table_2 中多于一行的所有行,反之亦然。

到目前为止,我已经尝试了这些相关的解决方案:

【问题讨论】:

  • 相似字段还是完全相同的字段?大约平均有多少重复?你的 Postgres 版本呢?

标签: sql postgresql join duplicates


【解决方案1】:

假设两个表具有相同的行类型:所有相同的列名和类型(至少兼容),您可以使用row types 来简化:

SELECT (t).*
FROM  (SELECT t, count(*) AS ct1 FROM table_1 t GROUP BY 1) t1
JOIN  (SELECT t, count(*) AS ct2 FROM table_2 t GROUP BY 1) t2 USING (t)
WHERE t1.ct1 > 1
   OR t2.ct2 > 1;
  1. 将重复项分组并记住每个表中的计数。
  2. 加入两个表,这会删除另一个表中所有不匹配的行。
  3. 过滤至少一侧有多个副本的行。
  4. 在外层SELECTdecompose the row type照常获取列。

我不返回行数。如果您需要这些,请在外部 SELECT 中添加 ct1ct2

这要求每个列类型都支持相等运算符=
一个突出的例子是json。 (但jsonb 确实如此。)请参阅:

如果您有这样的列,请转换为 text 以解决它。或者您可以使用哈希值 - 这也有助于非常宽的行和/或许多重复项的性能。相关:

【讨论】:

    【解决方案2】:

    从 table_1 中获取所有在 table_2 中有多个匹配记录的记录的一种方法是计算子查询中匹配记录的数量,并对其设置条件:

    SELECT * 
    FROM table_1 t1 
    WHERE (SELECT count(*) 
           FROM table_2 t2 
           WHERE t1.field_1 = t2.field_1) > 1
    

    如果您希望在一个查询中同时包含这两个方面,您可以将它们与 UNION 结合起来:

    SELECT * 
    FROM table_1 t1 
    WHERE (SELECT count(*) 
           FROM table_2 t2 
           WHERE t1.field_1 = t2.field_1) > 1
    UNION
    SELECT * 
    FROM table_2 t2 
    WHERE (SELECT count(*) 
           FROM table_1 t1 
           WHERE t1.field_1 = t2.field_1) > 1
    

    【讨论】:

    • 这将返回两个表中存在多个副本的重复项。此外,对于较大的表来说,为每一行执行一个相关的子查询是相当昂贵的。
    • 问题中使用的语言向我建议返回重复项是理想的行为,但您的答案肯定比我的要好。
    • 然后我把它倒过来了。 (但在这种情况下只报告行数会更有意义......)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-04
    • 1970-01-01
    • 2017-07-24
    • 2017-07-07
    • 2016-06-01
    • 1970-01-01
    相关资源
    最近更新 更多