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
子句和 GROUP
ing 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
我正在使用 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
子句和 GROUP
ing 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