如何使用窗口函数仅在 POSTGRES 中选择不超过某个值的行
Posted
技术标签:
【中文标题】如何使用窗口函数仅在 POSTGRES 中选择不超过某个值的行【英文标题】:How to select rows up to a certain value only in POSTGRES using window function 【发布时间】:2021-03-05 22:35:00 【问题描述】:我有一个名为 test 的表,并且只想选择它直到 1st 相同 id ('1144QQT') 的删除语句上方的行。所以,从 2021-03-01 到 2021-06-02(只有粗体)。因此,这不包括带有删除语句的行。它确实包含更多不同类型的 id 和更多相同类型的 id。
表架构:
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 做到这一点?是否可以使用窗口函数来做到这一点?
【问题讨论】:
您似乎已经知道存在窗口函数并且可以在此处使用它们,因为您对其进行了标记(好吧,您尝试了但在单词之间添加了一个空格而不是连字符,我为您更正了)。所以你应该继续自己尝试一些东西。如果这不能解决问题,那么edit 问题并包含您的合理 尝试以及详细 解释(错误消息、意外结果等) .). @Kraigolas 哈哈哈是的,我想我知道 where 语句是什么。我编辑了问题以使其更清楚,或者我希望如此。 @sticky bit 我的意思是我试过了。该语句基本上是更大查询的子查询。所以,我只是想简化它。虽然想不通。 【参考方案1】:根据您的描述,这个逻辑似乎可以满足您的需求:
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'
);
上述版本要求有一个“删除”——根据你的问题不清楚这是否是一个要求。另一种使用窗口函数:
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;
如果你想要所有行如果没有“删除”,那么将or min_delete_date is null
添加到外部where
。
【讨论】:
您好,但它确实包含更多不同类型的 id 和更多相同类型的 id。我只想将它选择到相同 id 的第一个删除语句上方的行。因此,从 2021-03-01 到 2021-03-06,不包括使用 delete 关键字的行。 类似最后一个解决方案的东西实际上是我正在寻找的。感谢您的帮助。【参考方案2】:使用SUM()
窗口函数,用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 |
【讨论】:
这也是一个不错的解决方案。非常感谢。【参考方案3】:我只想将它选择到相同 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
);
【讨论】:
以上是关于如何使用窗口函数仅在 POSTGRES 中选择不超过某个值的行的主要内容,如果未能解决你的问题,请参考以下文章
如何在带有 Postgres 的动态框架中使用窗口函数中的列值?
使用具有不同 order by 子句的 postgres 窗口函数