【问题标题】:PostgreSQL: Exclude duplicates as sorted by another keyPostgreSQL:排除按另一个键排序的重复项
【发布时间】:2021-02-03 16:39:06
【问题描述】:

考虑下表,它存储了某些对象的某些属性的更新历史记录,按effectivepublished 日期组织:

create table update_history(
  obj_id integer,
  effective date,
  published date,
  attr1 text,
  attr2 integer,
  attr3 boolean,
  primary key(obj_id, effective, published)
);
insert into update_history values
  (1, '2021-01-01', '2021-01-01', 'foo', null, null),
  (1, '2021-01-01', '2021-01-02', null, 1, false),
  (1, '2021-01-02', '2021-01-01', 'foo', 1, false),
  (1, '2021-01-02', '2021-01-02', 'bar', 1, false),
  (1, '2021-01-03', '2021-01-01', 'bar', 1, true),
  (1, '2021-01-04', '2021-01-01', 'bar', 1, true),
  (1, '2021-01-05', '2021-01-01', 'bar', 2, true),
  (1, '2021-01-05', '2021-01-02', 'bar', 1, true),
  (1, '2021-01-05', '2021-01-03', 'bar', 1, true),
  (1, '2021-01-06', '2021-01-04', 'bar', 1, true)
;

我需要编写一个 PostgreSQL 查询来简化给定 obj_id 的历史记录视图,方法是排除那些没有按照@987654327 的顺序更改前一个更新中的任何属性的更新记录@ 和 published 列。本质上,这些将是第 ## 6、9 和 10 行,在下表中以 斜体 标记:

# obj_id effective published attr1 attr2 attr3
1 1 2021-01-01 2021-01-01 foo (null) (null)
2 1 2021-01-01 2021-01-02 (null) 1 false
3 1 2021-01-02 2021-01-01 foo 1 false
4 1 2021-01-02 2021-01-02 bar 1 false
5 1 2021-01-03 2021-01-01 bar 1 true
6 1 2021-01-04 2021-01-01 bar 1 true
7 1 2021-01-05 2021-01-01 bar 2 true
8 1 2021-01-05 2021-01-02 bar 1 true
9 1 2021-01-05 2021-01-03 bar 1 true
10 1 2021-01-06 2021-01-04 bar 1 true

请记住,在现实生活中,要处理的属性要多得多,我不希望查询变得过于混乱。

我最接近预期结果的是使用rank 窗口函数:

select
  obj_id, effective, published,
  attr1, attr2, attr3
from (
  select *,
    rank() over (
      partition by attr1, attr2, attr3
      order by effective, published
    ) as rank
  from update_history
  where obj_id = 1) as d
where rank = 1
order by effective, published;

结果如下:

obj_id effective published attr1 attr2 attr3
1 2021-01-01 2021-01-01 foo (null) (null)
1 2021-01-01 2021-01-02 (null) 1 false
1 2021-01-02 2021-01-01 foo 1 false
1 2021-01-02 2021-01-02 bar 1 false
1 2021-01-03 2021-01-01 bar 1 true
1 2021-01-05 2021-01-01 bar 2 true

如您所见,原始表中的第 8 行被错误地排除在外,尽管它从前一行第 7 行更改为 attr2。显然,问题在于在窗口定义中排序之前应用了分区。

我想知道是否有另一种方法可以通过单个 PostgresSQL 查询来完成此操作。

【问题讨论】:

    标签: postgresql window-functions


    【解决方案1】:

    我会为此使用lag()

    select *
    from (
      select obj_id, effective, published,
             attr1, attr2, attr3, 
             (attr1, attr2, attr3) is distinct from lag( (attr1,attr2,attr3) ) over (partition by obj_id order by effective, published) as is_different
      from update_history
    ) t
    where is_different  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-10-29
      • 2018-03-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-19
      • 2018-10-23
      相关资源
      最近更新 更多