如何使用 window 函数仅在 POSTGRES 中 select 行达到特定值

How to select rows up to a certain value only in POSTGRES using window function

我有以下 table 命名测试,并且只想 select 它到 1st 相同 ID 删除语句上方的行('1144QQT')。所以,从 2021-03-01 到 2021-06-02(只有粗体)。因此,这排除了带有 delete 语句的行。它确实包括更多不同类型的 ID 和更多相同类型的 ID。

Table 架构:

CREATE TABLE test(
id                BIGINT       PRIMARY KEY NOT NULL,
barcode_id        VARCHAR      NOT NULL,
date              DATE         NOT NULL,
keyword           VARCHAR      NOT NULL
);

INSERT INTO test
VALUES
(1, '1144QQT', '2021-03-01'::date, 'insert'),
(2, '1144QQT', '2021-03-01'::date, 'insert'),
(3, '1144QQT', '2021-03-01'::date, 'insert'),
(4, '1144QQT', '2021-03-01'::date, 'insert'),
(5, '1144QQT', '2021-03-01'::date, 'insert'),
(6, '1144QQT', '2021-03-01'::date, 'insert'),
(7, '1144QQT', '2021-03-01'::date, 'insert'),
(8, '1144QQT', '2021-03-01'::date, 'insert'),
(9, '1144QQT', '2021-03-01'::date, 'insert'),
(10, '1144QQT', '2021-03-01'::date, 'insert'),
(11, '1144QQT', '2021-03-01'::date, 'insert');
id barcode_id date keyword
1 1144QQT 2021-03-01 insert
2 1144QQT 2021-03-02 adjust
3 5588aTT 2021-03-03 delete
4 4477aTT 2021-03-04 adjust
5 5588aTT 2021-03-05 adjust
6 1144QQT 2021-03-06 adjust
7 1144QQT 2021-03-07 delete
8 1144QQT 2021-03-08 insert
9 1144QQT 2021-03-09 adjust
10 1144QQT 2021-03-10 delete
11 4477aTT 2021-03-11 delete

所以,我期望的输出是这样的:

id barcode_id date keyword
1 1144QQT 2021-03-01 insert
2 1144QQT 2021-03-02 adjust
6 1144QQT 2021-03-06 adjust

我如何使用 postgres 执行此操作?是否可以使用 window 函数来做到这一点?

根据您的描述,此逻辑似乎符合您的要求:

select t.*
from t
where t.id = '1144QQT' and t.keyword <> 'delete';

这假设删除后没有 id 的行 -- 但这似乎是合理的,并且与您的样本数据一致。

对于您的具体问题,一种方法是相关子查询:

select t.*
from t
where t.id = '1144QQT' and
      t.id < (select min(t2.date)
              from t t2
              where t2.id = t.id and
                    t2.keyword <> 'delete'
             );

以上版本version要求有一个“delete”——根据你的问题不清楚是否有要求。另一种方法是使用 window 函数:

select t.*
from (select t.*,
             min(date) filter (where keyword = 'delete') over (partition by id) as min_delete_date
      where t.id = '1144QQT' 
     ) t
where date < min_delete_date;

如果你想要所有的行,如果没有“删除”,那么在外where.

上添加or min_delete_date is null

使用SUM() window函数识别第一行之前的行 keyword = 'delete':

SELECT id, date, keyword
FROM (
  SELECT *, SUM((keyword = 'delete')::int) OVER (ORDER BY date) grp
  FROM tablename
  WHERE id = '1144QQT'
) t
WHERE grp = 0

参见demo
结果:

id date keyword
1144QQT 2021-03-01 00:00:00 insert
1144QQT 2021-03-02 00:00:00 adjust
1144QQT 2021-03-06 00:00:00 adjust

I just want to Select it up to row above the 1st delete statement of the same id.

NOT EXISTS() 救援:(注意 date 是一个 保留字 ,并且是列的错误名称)

SELECT *
FROM ztable zt
WHERE zt.zid = '1144QQT'
AND NOT EXISTS (
    SELECT * FROM ztable nx
    WHERE nx.zid = zt.zid
    AND nx.zkeyword = 'delete'
    AND nx.zdate <= zt.zdate
    );