PostgreSQL - 如何 select 具有相同值的第一个连续组

PostgreSQL - How to select the first consecutive group having same value

我有一个包含 pkdept 列的 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();

它有点复杂,可能性能不佳,但您可以使用下面的代码实现您想要的。有四种操作:

  1. 第一个是我们获取基本订单和基本组 ID 的地方 为接下来的操作。
  2. 在第二个操作中,我们将技巧计算为一个唯一的组 每个组的 id
  3. 在第三个操作中,将唯一组id散布到哪里 每组的行。
  4. 最后,我们为每个组计算一个连续的组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 元组被删除。