Reputation: 5039
I'm trying to order a result set, it appears really simple, but I'm having a little trouble.
A person can have multiple address types, NULL, Civic or Mailing. I want anyone who has a NULL address to listed at the top, but then their civic and mailing address to follow.
If you don't have a null
address, then their civic and/or mailing address comes after anyone who has a null
.
I've tried ordering by address will just lists all null
s first, ordering by name, address, will work in part, but won't guarantee that the people will null
s will be first.
Take this set for example
ID Person Address
-------------------------
1 Person A Civic
1 Person A Mailing
2 Person B NULL
2 Person B Civic
2 Person B Mailing
3 Person C NULL
3 Person C Civic
3 Person C Mailing
Should be:
ID Person Address
-------------------------
2 Person B NULL
2 Person B Civic
2 Person B Mailing
3 Person C NULL
3 Person C Civic
3 Person C Mailing
1 Person A Civic
1 Person A Mailing
Upvotes: 2
Views: 61
Reputation: 51
You can try this one too
SELECT *
FROM @tab
ORDER BY Person,
(CASE
WHEN Address IS NULL
THEN 'a'
ELSE Address
END);
Upvotes: 0
Reputation: 22811
Simply
select *
from mytable
order by min(case when Address is null then 0 else 1 end) over (partition by ID), id, Address;
Although Sql Server doesn't accept a window function in WHERE it's OK in ORDER BY. So you needn't any subquery here.
Upvotes: 0
Reputation: 5031
Try with this CTE version.
;WITH CTE_1
AS (SELECT Id, Person, Address,
SUM(CASE WHEN PERSON IS NULL THEN 1 ELSE 0 END) OVER
(PARTITION BY person) AS RNO
FROM addresses)
SELECT Id, Person, Address
FROM CTE_1
ORDER BY RNO DESC, person ASC, address ASC
Upvotes: 1
Reputation: 312257
Tim Biegeleisen has the right idea with regard to count the number of records where address IS NULL
. I think the query could be made a tad more elegant (and probably perform a bit better) by using sum
with a windows clause instead of joining on it with a subquery:
SELECT id, person, address
FROM (SELECT id,
person,
address,
SUM(CASE WHEN PERSON IS NULL THEN 1 ELSE 0 END) OVER
(PARTITION BY person) AS s
FROM addresses) t
ORDER BY s DESC, person ASC, address ASC
Upvotes: 1
Reputation: 522762
This solution uses a subquery which determines whether or not each ID
(person) has a NULL
value one his addresses. If a person does have a NULL
value, then a tally kept will have a sum greater than zero. Those persons with at least one NULL
address are then ordered first before those persons without at least one NULL
. After this, the result set is ordered by ID
followed by Address
, as you might already have been doing.
SELECT t1.*
FROM yourtable
INNER JOIN
(
SELECT ID,
SUM(CASE WHEN Address IS NULL THEN 1 END) AS hasNull
FROM yourTable
GROUP BY ID
) t2
ON t1.ID = t2.ID
ORDER BY CASE WHEN t2.hasNull > 0 THEN 0 ELSE 1 END,
t1.ID,
t1.Address
Upvotes: 2