Reputation: 5846
I have a strange scenario where I need to return the right-most non-zero column in a table structured as follows:
GL Q1 Q2 Q3 Q4
1 100 0 0 0
2 100 900 250 0
3 600 100 0 1000
I am expecting the output to be:
GL Amount
1 100
2 250
3 1000
Is there anyway to accomplish this as a set-based approach without having to resort to a CASE statement or similar solution? Performance is going to be important here.
Upvotes: 5
Views: 2098
Reputation: 13157
SELECT
GL,
COALESCE( NULLIF(Q4,0), NULLIF(Q3,0), NULLIF(Q2,0), NULLIF(Q1,0) ) as Amount
FROM
myTable
Upvotes: 11
Reputation: 175766
Set based-ish based on alpha sorting of "Q?" (Assumes not all quarters are 0)
with T as (
select GL, Q, VALUE, row_number() over (partition by GL order by Q desc) as row
from (
select GL,Q1,Q2,Q3,Q4 from theTable
) T
unpivot (VALUE for Q in (Q1,Q2,Q3,Q4)) as U
where VALUE <> 0
)
select * from T
where row = 1
Upvotes: 1
Reputation:
SELECT
COALESCE(NULLIF(Q4,0),NULLIF(Q3,0),NULLIF(Q2,0),NULLIF(Q1,0))
Upvotes: 1
Reputation: 110111
Case statement is correct to use here. It is the most performant option available.
SELECT GL,
CASE
WHEN Q4 != 0 THEN Q4
WHEN Q3 != 0 THEN Q3
WHEN Q2 != 0 THEN Q2
ELSE Q1
END
FROM TheTable
If you require a set based approach - you'd have to PIVOT and then aggregate by RowNumber. That's slower.
Upvotes: 1
Reputation: 86716
There is no SET based approach, as SQL is designed to aggregate across rows, not columns.
I would actually expect CASE to be pretty fast here...
CASE WHEN Q4 <> 0 THEN Q4
WHEN Q3 <> 0 THEN Q3
WHEN Q2 <> 0 THEN Q2
WHEN Q1 <> 0 THEN Q1
ELSE NULL
END
There is, however, an alternative using NULLs and COALESCE...
COALESCE(NULLIF(Q4, 0), NULLIF(Q3, 0), NULLIF(Q2, 0), NULLIF(Q1, 0))
Upvotes: 4