根据这些行之间的条件过滤Postgres中的重复行

时间:2019-03-07 17:10:29

标签: sql postgresql

提供表格

CREATE TABLE data(
 irs_number VARCHAR (50),
 mop_up INTEGER,
 ou VARCHAR (50)
);

我如何返回所有匹配的记录...

  • 另一行中的irs_number至少具有一个相同的值,并且
  • 至少mop_up个具有相同irs_number的用户必须设置为1并且
  • ou的值不相同,即只返回与相同的irs_number不匹配的那些值。

...,以便返回所有irs_numbers(不仅是满足条件的一个-参见下面的示例)。

我尝试了此操作,但是查询无法在合理的时间内完成:

SELECT irs_number, mop_up, ou
FROM data outer_data
WHERE (SELECT count(*)
FROM data inner_data
WHERE inner_data.irs_number = outer_data.irs_number
AND inner_data.mop_up = 1 OR outer_data.mop_up = 1
AND inner_data.ou <> outer_data.ou
);

以及此处描述的重复计数的变化形式:How to find duplicate records in PostgreSQL-它们将始终仅返回重复计数,但不会应用适当的过滤器。


修改

示例数据:

INSERT INTO data VALUES 
('0001', 1, 'abc'),
('0001', 0, 'abc'),
('0001', 0, 'cde'),
('0001', 0, 'abc'),
('0002', 1, 'abc'),
('0002', 0, 'abc'),
('0003', 0, 'abc'),
('0003', 0, 'xyz')
;

SQLFiddle:http://sqlfiddle.com/#!17/be28f

理想情况下,查询应返回:

irs_number  mop_up  ou
-----------------------
0001        1       abc
0001        0       abc
0001        0       cde
0001        0       abc

(顺序不重要) 表示它应返回所有匹配irs_number与以上条件的行。

2 个答案:

答案 0 :(得分:1)

我认为此联接可以做到:

SELECT * FROM data 
WHERE irs_number in (
  SELECT irs_number
  FROM data d
  WHERE EXISTS (SELECT 1
    FROM data 
    WHERE irs_number = d.irs_number
    AND (mop_up = 1 OR d.mop_up = 1)
    AND ou <> d.ou
  )
)

请参见demo

答案 1 :(得分:1)

您应该可以使用简单的exists子句来做到这一点:

SELECT irs_number, mop_up, ou
FROM data d
WHERE EXISTS (SELECT 1
              FROM data d2
              WHERE d2.irs_number = d.irs_number AND
                    d2.mop_up = 1 AND
                    d2.ou <> d.ou
             );

编辑:

以上内容误解了这个问题。它假定mop_up = 1必须位于不同 ou上。当我阅读问题时,这是模棱两可的,但似乎不是您想要的。因此,两个exists解决了这个问题:

SELECT irs_number, mop_up, ou
FROM data d
WHERE EXISTS (SELECT 1
              FROM data d2
              WHERE d2.irs_number = d.irs_number AND
                    d2.mop_up = 1
             ) AND
     EXISTS (SELECT 1
              FROM data d2
              WHERE d2.irs_number = d.irs_number AND
                    d2.ou <> d.ou
             );

Here是db <>小提琴。

这两种解决方案都将能够利用(irs_number, mop_up, ou)上的索引。