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()
.
解决了这个问题
我在 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()
.