Reputation: 55
I have a situation where I have a Customer table and I need to locate document numbers from a column which is structured as a string where the first 4 characters represent the type of document (e.g.,'BILL000000000001', 'PYMT000000000001'). Each of these documents also has a corresponding document date. I want to fetch the CustomerNumber where the DocType is BILL with the max(DocDate) and return the CustomerNumber and the DocDate. This part is fairly straightforward and presents no challenge.
My problem is that some customers do not as yet have a document starting with 'BILL'. For those, I want to fetch the CustomerNumber and max(DocDate) that matches another string XXXX as the first 4 characters. In essence, I need to use some sort of conditional expression that fetches either the CustomerNumber and max(DocDate) for a BILL type, or the Customer Number and max(DocDate) for a XXXX type of record. The issue is that there is a possibility that both a BILL and XXXX type might exist for a Customer. Where a BILL exists, I want to pick the CustomerNumber and max(DocDate) for that customer. However, where an XXXX type exists but no BILL type document is available, I need the CustomerNumber and max(DocDate) for type XXXX.
I was thinking of using EXCEPT and UNION but I don't think either option really works for me. Here's my SQL with EXCEPT, if it helps at all.
select CustomerNumber, max(DocDate)
FROM Table1
where substring(DocumentNumber,1,4) = 'BILL'
group by CustomerNumber
EXCEPT
select CustomerNumber, max(DocDate)
from Table1
where substring(umDocumentNumber,1,4) = 'MISC'
group by CustomerNumber
Upvotes: 0
Views: 71
Reputation: 1269773
You can do what you want using aggregation:
select CustomerNumber,
coalesce(max(case when DocumentNumber like 'BILL%' then DocDate end),
max(DocumentNumber)
)
from Table1
where DocumentNumber like 'BILL%' or DocumentNumber like 'MISC%'
group by CustomerNumber;
Or using window functions:
select t1.*
from (select t1.*,
row_number() over (partition by CustomerNumber
order by left(DocumentNumber, 4), DocDate desc
) as seqnum
from Table1 t1
) t1
where seqnum = 1;
This method allows you to return the entire row for the maximum document.
Upvotes: 3
Reputation: 8101
If I understand your logic, you need the CustomerNumber
and MAX(DocDate)
for customers that have a BILL
type record, and you also need the CustomerNumber
and MAX(DocDate)
for any customers where a BILL
type record does not exist.
A UNION
of your initial results and another result set that includes a WHERE NOT EXISTS
clause should return what you're looking for.
SELECT
CustomerNumber
,max(DocDate)
FROM Table1
WHERE substring(DocumentNumber, 1, 4) = 'BILL'
GROUP BY CustomerNumber
UNION ALL
SELECT
CustomerNumber
,max(DocDate)
FROM Table1 AS out
WHERE
NOT EXISTS (SELECT 1
FROM Table1 AS in
WHERE
in.CustomerNumber = out.CustomerNumber
AND
substring(umDocumentNumber, 1, 4) = 'BILL'
GROUP BY CustomerNumber;
Upvotes: 2