PostgreSQL - 如何 select 具有相同值的第一个连续组
PostgreSQL - How to select the first consecutive group having same value
我有一个包含 pk
和 dept
列的 table:
pk dept
-------
27 A
29 A
30 B
31 B
33 A
我需要 select 第一个连续组 ,即当 table按pk
排序,即预期结果为:
pk dept
-------
27 A
29 A
在我的示例中有 3 个连续的组(AA、BB 和 A)。群组人数不限(可超过2人)。
我不确定我是否理解你的问题,但是对于每个 dept
的第一个 pk
你可以试试这个:
select min(pk) as pk,
dept
from your_table
group by dept
记住存储函数。与使用 window 函数不同,它允许避免读取整个 table:
--drop function if exists foo();
--drop table if exists t;
create table t(pk int, dep text);
insert into t values(27,'A'),(29,'A'),(30,'B'),(31,'B'),(33,'A');
create function foo() returns setof t language plpgsql as $$
declare
r t;
p t;
begin
for r in (select * from t order by pk) loop
if p is null then
p := r;
end if;
exit when p.dep is distinct from r.dep;
return next r;
end loop;
return;
end $$;
select * from foo();
它有点复杂,可能性能不佳,但您可以使用下面的代码实现您想要的。有四种操作:
- 第一个是我们获取基本订单和基本组 ID 的地方
为接下来的操作。
- 在第二个操作中,我们将技巧计算为一个唯一的组
每个组的 id
- 在第三个操作中,将唯一组id散布到哪里
每组的行。
- 最后,我们为每个组计算一个连续的组id,以允许
组的自由选择,所以我们只需要过滤
我们要获取的组号。
希望对您有所帮助。
SELECT fourthOperation.pk,
fourthOperation.dept
FROM (SELECT thirdOperation.pk,
thirdOperation.dept,
DENSE_RANK() OVER (ORDER BY thirdOperation.spreadedIdGroup) denseIdGroup
FROM (SELECT secondOperation.*,
NVL(idGroup, LAG(secondOperation.idGroup IGNORE NULLS) OVER (ORDER BY secondOperation.numRow)) spreadedIdGroup
FROM (SELECT firstOperation.*,
CASE WHEN LAG(firstOperation.rankRow) OVER (ORDER BY firstOperation.numRow) = firstOperation.rankRow
THEN NULL
ELSE firstOperation.numRow
END idGroup
FROM (SELECT yourTable.*,
ROW_NUMBER() OVER (ORDER BY PK) AS numRow,
DENSE_RANK() OVER (ORDER BY DEPT) AS rankRow
FROM ABORRAR yourTable) firstOperation) secondOperation ) thirdOperation) fourthOperation
WHERE fourthOperation.denseIdGroup = 1
以下查询应该可以满足您的要求(我将您的 table tx 命名为):
SELECT *
FROM tx t1
WHERE NOT EXISTS (
SELECT *
FROM tx t2
WHERE t2.dept <> t1.dept
AND t2.pk < t1.pk);
想法是寻找元组,使得不存在具有较小 pk 和不同部门的元组。
- 保留前两个A元组;
- 由于前两个 A 元组,B 元组被丢弃;
- 由于 B 元组,最后一个 A 元组被删除。
我有一个包含 pk
和 dept
列的 table:
pk dept
-------
27 A
29 A
30 B
31 B
33 A
我需要 select 第一个连续组 ,即当 table按pk
排序,即预期结果为:
pk dept
-------
27 A
29 A
在我的示例中有 3 个连续的组(AA、BB 和 A)。群组人数不限(可超过2人)。
我不确定我是否理解你的问题,但是对于每个 dept
的第一个 pk
你可以试试这个:
select min(pk) as pk,
dept
from your_table
group by dept
记住存储函数。与使用 window 函数不同,它允许避免读取整个 table:
--drop function if exists foo();
--drop table if exists t;
create table t(pk int, dep text);
insert into t values(27,'A'),(29,'A'),(30,'B'),(31,'B'),(33,'A');
create function foo() returns setof t language plpgsql as $$
declare
r t;
p t;
begin
for r in (select * from t order by pk) loop
if p is null then
p := r;
end if;
exit when p.dep is distinct from r.dep;
return next r;
end loop;
return;
end $$;
select * from foo();
它有点复杂,可能性能不佳,但您可以使用下面的代码实现您想要的。有四种操作:
- 第一个是我们获取基本订单和基本组 ID 的地方 为接下来的操作。
- 在第二个操作中,我们将技巧计算为一个唯一的组 每个组的 id
- 在第三个操作中,将唯一组id散布到哪里 每组的行。
- 最后,我们为每个组计算一个连续的组id,以允许 组的自由选择,所以我们只需要过滤 我们要获取的组号。
希望对您有所帮助。
SELECT fourthOperation.pk,
fourthOperation.dept
FROM (SELECT thirdOperation.pk,
thirdOperation.dept,
DENSE_RANK() OVER (ORDER BY thirdOperation.spreadedIdGroup) denseIdGroup
FROM (SELECT secondOperation.*,
NVL(idGroup, LAG(secondOperation.idGroup IGNORE NULLS) OVER (ORDER BY secondOperation.numRow)) spreadedIdGroup
FROM (SELECT firstOperation.*,
CASE WHEN LAG(firstOperation.rankRow) OVER (ORDER BY firstOperation.numRow) = firstOperation.rankRow
THEN NULL
ELSE firstOperation.numRow
END idGroup
FROM (SELECT yourTable.*,
ROW_NUMBER() OVER (ORDER BY PK) AS numRow,
DENSE_RANK() OVER (ORDER BY DEPT) AS rankRow
FROM ABORRAR yourTable) firstOperation) secondOperation ) thirdOperation) fourthOperation
WHERE fourthOperation.denseIdGroup = 1
以下查询应该可以满足您的要求(我将您的 table tx 命名为):
SELECT *
FROM tx t1
WHERE NOT EXISTS (
SELECT *
FROM tx t2
WHERE t2.dept <> t1.dept
AND t2.pk < t1.pk);
想法是寻找元组,使得不存在具有较小 pk 和不同部门的元组。
- 保留前两个A元组;
- 由于前两个 A 元组,B 元组被丢弃;
- 由于 B 元组,最后一个 A 元组被删除。