I have a table using SQL Server 2008 it has a table with two sortable columns on it one is manually set and the other is calculated by a system procedure (this procedure sorts everything as a whole and assigns a sort starting at 10 until the highest row number times 10)
ID Manual System
------------------------
1 null 300
2 2 380
3 null 500
4 null 200
And I am trying to get it to sort the ids to be 4,2,1,3
I would like the output to take the Manual Sort over the System when it has been applied. to further complicate things if another row is added and it has a manual sort that also needs to be considered.
ID Manual System
-----------------------
1 null 300
2 2 380
3 null 500
4 null 200
5 5 100
so the new sort would be 4,2,1,3,5
ID Manual System
-----------------------
4 null 200
2 2 380
1 null 300
3 null 200
5 5 100
Any ideas? and I have tried Rank, Dense_Rank, Row_Number etc.
The solutions that have been given seem correct for my example. I forgot to mention there is a third column personID that is also a factor here.
ID Manual System PersonID
-------------------------------------
4 null 200 22
2 2 380 22
1 null 300 22
3 null 200 22
5 5 100 22
8 1 210 25
6 1 480 25
7 null 600 25
9 4 800 25
10 null 990 25
So I first have to order them by person then, order them by Manual then by sort. which still seems to give me an issue.
Here is my solution: http://sqlfiddle.com/#!3/a32a0/1/0
SELECT *
FROM
(
SELECT
ID
, ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY System)-.1 AS rn
, Manual
, System
, PersonID
FROM YourTable
) t0
ORDER BY PersonID
, COALESCE(Manual, RN)
Here is the explanation:
PARTITION BY...
before I ORDER BY...
this resets the index for each grouping of MANUAL
ROW_NUMBER
and the MANUAL
sorting, I subtract .1 (arbitrary amount between (0,1)). This gives preference to the MANUAL
value in case of a tieORDER BY
the PARTITION BY
value first, ensuring the proper grouping first, then I order by the first non-null value of MANUAL
and RN
Give it a try. +points to the starting points of the previous two answers. I used one of them as a starting point and re-wrote from there.
EDIT: Removed the subtraction of .1 and added a new ranking function which "tricks" the optimizer into preferring manual over rank. I have no idea if this holds up in all cases or if the optimizer will fail to give the results in this order under other circumstances, but I wanted to include the findings just in case they're helpful.
My updated query is as follows:
SELECT *
FROM
(
SELECT
ID
, ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY System) AS rn
, ROW_NUMBER() OVER (PARTITION BY PersonID ORDER BY Manual) AS rn_throwaway
, Manual
, System
, PersonID
FROM YourTable
) t0
ORDER BY PersonID
, COALESCE(Manual, RN)
And examples of it in use are at http://sqlfiddle.com/#!3/1831d/55/0 and http://sqlfiddle.com/#!3/a32a0/9/0
If I'm understanding your requirements, you want to sort by the System column, unless the Manual column is supplied, and in which case, use that as the sort position instead? If so, then this should work for you using CASE
and ROW_NUMBER
:
SELECT Id, Manual, System
FROM (
SELECT Id,
Manual,
System,
ROW_NUMBER() OVER (ORDER BY Manual, System) rn
FROM YourTable) t
ORDER BY CASE WHEN Manual IS NULL THEN RN ELSE Manual END, COALESCE(Manual,RN+1)
SQL Fiddle Demo
I think this is what you need. It is bit difficult to explain.
Basically inserting not null manual values as row index (or row number) to the record list ordered by system.
FIDDLE DEMO
;with cte as (
select id, manual,system,
convert(decimal(10,1),row_number() over(order by system)) rn
from t
where manual is null
union all
select id, manual,system, convert(decimal(10,1),manual-0.5) rn
from t
where manual is not null
)
select id,manual,system
from cte
order by rn
| ID | MANUAL | SYSTEM |
------------------------
| 4 | (null) | 200 |
| 2 | 2 | 380 |
| 1 | (null) | 300 |
| 3 | (null) | 500 |
| 5 | 5 | 100 |
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With