1

I have a situation in PostgreSQL that I'm struggling with. The schema/model that I'm working with is not under my control and not something I'm able to alter, so I am trying to figure out the best way to deal with the cards I've been dealt.

First, the schema, simplified for this question, but essentially it's invoice (Type = T) and transaction (Type <> T) lines combined into the same table. There can and will be n-number of tranaction lines per invoice and n-number of invoices per client that can be intermingled as seen below.

Given this schema:

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

and this data:

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');

which looks like:

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

the result I'm looking for:

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

Playing with an answer from a previous question, I came up with:

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';

Which gets me close:

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

The only issue here is that record with Id = 1 should have imputed_invoiceno = 97, but doesn't and I'm unclear as to why.

1 Answer 1

2

Something strange is going on with the string type. You get the expected results with this query using numbers:

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';

Note that I changed the max() to a min().

Here is a db<>fiddle.

The issue is that the ordering for strings is not what you expect. It is not 0 < 97 < 98 < 99 < 100. It is '0' < '100' < '97' < '98' < '99'. I think you worked around this using max().

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.