SQL GROUP BY及其后的缩减版本

问题描述

我正在使用Postgresql v.11。我有一张三列的桌子。我的目标是在数据内部发现冗余。

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

SELECT client,block,"date"
FROM lines
GROUP BY client,"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行就是这种情况(block = P10002)

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

但是在纯sql中,有没有办法提取出这种“减少的”结果呢?

预期结果是这样

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

最好将两个日期保留在结果集中,因为我只需要更改其中一个的“块”即可。如果结果集中没有date列,则需要再次请求查找所有受影响的行。

这是表和数据的脚本

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'),'2020-05-04'),'P10003','2020-05-05');

非常感谢

解决方法

您可以将HAVING子句与GROUPBY block一起使用,以明确计数dates

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


block
------
P10002
,

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

查询看起来像这样。

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

您可以使用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(*)都没有重复的日期,则还可以使用select client,block,date from ( select *,count(*) over (partition by client,block) counter from lines ) t where counter > 1 窗口函数:

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

请参见demo
结果:

  getData(): Observable<{items: MyData[]}> {
    return new Observable(subscriber => {
      this.myNext(subscriber);
    });;
  }
,

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

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

如前所述,该代码无处不在-它们对NULL的排序可能不同。

WITH
lines(client,dt) AS (
          SELECT 1,'P10001',DATE '2020-01-01'
UNION ALL SELECT 1,'P10002',DATE '2020-04-17'
UNION ALL SELECT 1,DATE '2020-05-04'
UNION ALL SELECT 1,'P10003',DATE '2020-05-05'
UNION ALL SELECT 1,DATE '2020-05-05'
)
SELECT
  client,dt
FROM lines
UNION ALL
SELECT
  client,NULL::DATE AS dt
FROM lines
GROUP BY
  client,block
ORDER BY
  client,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