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

时间:2017-01-09 16:46:42

标签: sql postgresql gaps-and-islands

我有一个包含pkdept列的表格:

pk dept
-------
27  A
29  A
30  B
31  B
33  A

我需要选择第一个连续的组,这是第一个连续的行集,当dept排序表时,它们都具有相同的pk值,即预期的结果是:

pk dept
-------
27  A
29  A

在我的例子中,有3个连续的组(AA,BB和A)。组的大小是无限的(可以超过2)。

4 个答案:

答案 0 :(得分:2)

以下查询应该执行您想要的操作(我将您的表命名为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元组,最后一个元组被删除。

答案 1 :(得分:0)

记住存储的功能。与使用窗口函数不同,它允许避免读取整个表:

--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();

答案 2 :(得分:0)

它有点复杂,可能,性能很差,但你可以使用下面的代码实现你想要的。有四个操作:

  1. 第一个是我们获取基本订单和基本组ID的地方 用于下一次操作。
  2. 在第二个操作中,我们制定计算一个独特组的技巧 每个组的ID
  3. 在第三个操作中,将唯一组ID传播到哪里 每组的行。
  4. 最后,我们计算每个组允许的连续组ID 组的自由选择,所以我们只需要过滤 我们想要获得的组号。
  5. 希望这有帮助。

    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                                   
    

答案 3 :(得分:-2)

我不确定我是否理解您的问题,但对于每个pk的第一个dept,您可以尝试这样做:

select min(pk) as pk,
       dept
from your_table
group by dept