PostgreSQL, Window 函数使用问题(附具体例子)

PostgreSQL, Window function usage question (with specific example)

我在 PostgreSQL 中遇到了一个我正在努力解决的问题。我正在使用的 schema/model 不在我的控制之下,也不是我能够改变的东西,所以我试图找出处理我已经处理过的牌的最佳方法。

首先,架构针对这个问题进行了简化,但本质上是将发票 (Type = T) 和交易 (Type <> T) 行合并到同一个 table 中。每个发票可以并且将会有 n 个交易行,每个客户可以有 n 个发票,如下所示。

鉴于此架构:

CREATE TABLE t (
id serial PRIMARY KEY,
Type VARCHAR (50) NOT NULL,
InvoiceNo VARCHAR (50) NOT NULL,
ClientId VARCHAR (50) NOT NULL);

和此数据:

insert into t (type, InvoiceNo, ClientId) values ('X', '0', '1');
insert into t (type, InvoiceNo, ClientId) values ('I', '97', '1');
insert into t (type, InvoiceNo, ClientId) values ('S', '0', '2');
insert into t (type, InvoiceNo, ClientId) values ('X', '0', '2');
insert into t (type, InvoiceNo, ClientId) values ('S', '0', '1');
insert into t (type, InvoiceNo, ClientId) values ('I', '98', '2');
insert into t (type, InvoiceNo, ClientId) values ('S', '0', '1');
insert into t (type, InvoiceNo, ClientId) values ('X', '0', '1');
insert into t (type, InvoiceNo, ClientId) values ('I', '99', '1');
insert into t (type, InvoiceNo, ClientId) values ('T', '0', '1');
insert into t (type, InvoiceNo, ClientId) values ('S', '0', '1');
insert into t (type, InvoiceNo, ClientId) values ('X', '0', '1');
insert into t (type, InvoiceNo, ClientId) values ('I', '100', '1');

看起来像:

Id Type InvoiceNo ClientId
1 X 0 1
2 I 97 1
3 S 0 2
4 X 0 2
5 S 0 1
6 I 98 2
7 S 0 1
8 X 0 1
9 I 99 1
10 T 0 1
11 S 0 1
12 X 0 1
13 I 100 1

我要的结果:

Id Type InvoiceNo ClientId
12 X 100 1
11 S 100 1
10 T 100 1
8 X 99 1
7 S 99 1
5 S 99 1
1 X 97 1
4 X 98 2
3 S 98 2

根据上一个问题的答案,我想到了:

select * from (select t.*,
   max(InvoiceNo) filter (where type = 'I') over (partition by clientid order by id DESC) as imputed_invoiceno 
from t) as x
where Type <> 'I';

这让我很接近:

Id Type InvoiceNo ClientId imputed_invoiceno
12 X 0 1 100
11 S 0 1 100
10 T 0 1 100
8 X 0 1 99
7 S 0 1 99
5 S 0 1 99
1 X 0 1 99
4 X 0 2 98
3 S 0 2 98

这里唯一的问题是 ID = 1 的记录应该有 imputed_invoiceno = 97,但没有,我不清楚为什么。

字符串类型发生了一些奇怪的事情。您使用数字获得此查询的预期结果:

select *
from (select t.*,
             min(InvoiceNo) filter (where type = 'I') over (partition by clientid order by id desc) as imputed_invoiceno 
      from t
     ) x
where Type <> 'I';

请注意,我将 max() 更改为 min()

Here 是一个 db<>fiddle.

问题是字符串的顺序不是您所期望的。它不是 0 < 97 < 98 < 99 < 100。是'0' < '100' < '97' < '98' < '99'。我认为您使用 max().

解决了这个问题