SQL GROUP BY 并在之后重新归约

SQL GROUP BY and kind of rereduce afterwards

我正在使用 PostgreSQL v.11。我有一个包含 3 列的 table。我的目标是在数据中找到冗余。

首先,我做一个简单的 GROUP BY:

SELECT client, block, "date"
FROM lines
GROUP BY client, block, "date"
ORDER BY client, block

结果如下所示:

1 | P10001 | 2020-01-01
1 | P10002 | 2020-04-17
1 | P10002 | 2020-05-04
1 | P10003 | 2020-05-05

现在我想识别具有相同“块”但不同“日期”的行。在此示例中,第 2 行和第 3 行就是这种情况(块 = P10002)

现在,我使用 javascript 来解析完整的结果集并找到这 2 个冗余行(我使用 result.reduce(...)

但是有没有办法在纯 SQL 中提取这个“重新减少”的结果?

预期结果是这样的:

1 | P10002 | 2020-04-17
1 | P10002 | 2020-05-04

将这两个日期保留在结果集中应该很好,因为我只需要更改其中一个的“块”。如果结果集中没有日期列,我将需要执行第二个请求以查找所有受影响的行。

这是 table 和数据

的脚本
CREATE TABLE lines (
  "client" integer NOT NULL,
  "block" text NOT NULL,
  "date" date NOT NULL
);

INSERT INTO lines ("client", "block", "date") VALUES
  (1, 'P10001', '2020-01-01'),
  (1, 'P10002', '2020-04-17'),
  (1, 'P10002', '2020-05-04'),
  (1, 'P10003', '2020-05-05');

非常感谢

您可以使用 HAVING 子句和 GROUPing BY block 来明确计算 dates :

SELECT block
  FROM lines
 GROUP BY block
HAVING COUNT( DISTINCT "date" ) > 1;


block
------
P10002

这适用于所有数据库管理系统。

一些 DBMS(您未指定)也提供 GROUP BY ROLLUP()。在您的 DBMS 文档中查找。

如前所述,这个在任何地方都有效——他们可能对 NULL 进行不同的排序。

WITH
lines(client,block,dt) AS (
          SELECT 1,'P10001',DATE '2020-01-01'
UNION ALL SELECT 1,'P10002',DATE '2020-04-17'
UNION ALL SELECT 1,'P10002',DATE '2020-05-04'
UNION ALL SELECT 1,'P10003',DATE '2020-05-05'
UNION ALL SELECT 1,'P10001',DATE '2020-01-01'
UNION ALL SELECT 1,'P10002',DATE '2020-04-17'
UNION ALL SELECT 1,'P10002',DATE '2020-05-04'
UNION ALL SELECT 1,'P10003',DATE '2020-05-05'
)
SELECT
  client
, block
, dt
FROM lines
UNION ALL
SELECT
  client
, block
, NULL::DATE AS dt
FROM lines
GROUP BY
  client
, block
ORDER BY
  client
, block
, dt
-- out  client | block  |     dt     
-- out --------+--------+------------
-- out       1 | P10001 | 
-- out       1 | P10001 | 2020-01-01
-- out       1 | P10001 | 2020-01-01
-- out       1 | P10002 | 
-- out       1 | P10002 | 2020-04-17
-- out       1 | P10002 | 2020-04-17
-- out       1 | P10002 | 2020-05-04
-- out       1 | P10002 | 2020-05-04
-- out       1 | P10003 | 
-- out       1 | P10003 | 2020-05-05
-- out       1 | P10003 | 2020-05-05

您应该使用 HAVING 子句来获取冗余数据集。我假设您在冗余检测中也需要客户端。

查询看起来像这样。

SELECT client, block
FROM lines
GROUP BY client, block
HAVING count(distinct "date") > 1
ORDER BY client, block

你可以用 EXISTS:

select l.* from lines l
where exists (
  select 1 from lines
  where client = l.client and block = l.block and date <> l.date
)

如果每个 client, block 没有重复日期的情况,您还可以使用 COUNT(*) window 函数:

select client, block, date
from (
  select *, count(*) over (partition by client, block) counter
  from lines
) t
where counter > 1

参见demo
结果:

> client | block  | date      
> -----: | :----- | :---------
>      1 | P10002 | 2020-04-17
>      1 | P10002 | 2020-05-04