简体   繁体   中英

Sort results by number of NOT NULL values

I have a query where each row consists of 3 columns:

  1. Name
  2. Distance
  3. Proximity

I want to sort the rows based on number of NOT NULL (ie present) values exactly as follows:

  1. All values are present
  2. Two values are present in this order
    • Name and Distance
    • Name and Proximity
    • Distance and Proximity
  3. One value is present
    • Name
    • Distance
    • Proximity

Here is sample data (insert statements are sorted in the order i expect):

/*
CREATE TABLE #TEMP (
    Type      VARCHAR(100),
    Name      VARCHAR(100),
    Distance  VARCHAR(100),
    Proximity VARCHAR(100)
);
*/
INSERT INTO #TEMP VALUES ('AIRPORT', 'KBLI', '21mi', 'City')
INSERT INTO #TEMP VALUES ('AIRPORT', 'KBLI', '21mi',  NULL )
INSERT INTO #TEMP VALUES ('AIRPORT', 'KBLI',  NULL , 'City')
INSERT INTO #TEMP VALUES ('AIRPORT',  NULL , '21mi', 'City')
INSERT INTO #TEMP VALUES ('AIRPORT', 'KBLI',  NULL ,  NULL )
INSERT INTO #TEMP VALUES ('AIRPORT',  NULL , '21mi',  NULL )
INSERT INTO #TEMP VALUES ('AIRPORT',  NULL ,  NULL , 'City')

I have had some success with COALESCE statement but I am looking for something efficient and readable. Later I will change to four columns.

Assign a present value as if it were a number (a name=4, a distance=3, a proximity=2), then sum them and sort by that:

select ...
from ...
order by
  case when name is null then 0 else 4 end +
  case when distance is null then 0 else 3 end +
  case when proximity is null then 0 else 2 end desc

The trick here is that 3+2 > 4, so a distance and proximity beats a name.

This doesn't have any cool fancy math, but if you were to have multiple values for the same [type] then mine would sort those in order as well.

SELECT  *
FROM #Temp
ORDER BY    [Type],

            LEN(CONCAT(LEFT(Name,1),LEFT(Distance,1),LEFT(Proximity,1))) DESC, --counts number of non null columns                       
            --LEN(ISNULL(LEFT(Name,1),'') + ISNULL(LEFT(Distance,1),'') + ISNULL(LEFT(Proximity,1),'')) DESC, /*SQL 2008R2 and below alternative for counting non-null columns*/ 

            ISNULL(Name,'zz'), --ISNULL then 'zz' which when ordered, goes at the end
            ISNULL(Distance,'zz'),
            ISNULL(Proximity,'zz')

For the general question, you can use:

order by ((case when name is not null then 1 else 0 end) + 
          (case when distance is not null then 1 else 0 end) + 
          (case when proximity is not null then 1 else 0 end)
         ) desc

EDIT:

I didn't realize you wanted sub-ordering as well. You might have to list out all the possibilities:

order by (case when name is not null and proximity is not null and distance is not null then 1
               when name is not null and distance is not null then 2
               when name is not null and proximity is not null then 3
               when proximity is not null and distance is not null then 4
               when name is not null then 5
               when distance is not null then 6
               when proximity is not null then 7
               else 8
          end)

This should do it:

SELECT t.*
FROM dbo.Tablename t
ORDER BY 
    CASE WHEN Name       IS NOT NULL 
          AND Distance   IS NOT NULL 
          AND Proximity  IS NOT NULL THEN 0 ELSE 1 END ASC,
     CASE WHEN Name      IS NOT NULL 
          AND Distance   IS NOT NULL THEN 0 ELSE 1 END ASC,
     CASE WHEN Name      IS NOT NULL 
          AND Proximity  IS NOT NULL THEN 0 ELSE 1 END ASC,
     CASE WHEN Distance  IS NOT NULL 
          AND Proximity  IS NOT NULL THEN 0 ELSE 1 END ASC,
     CASE WHEN Name      IS NOT NULL THEN 0 ELSE 1 END ASC,
     CASE WHEN Distance  IS NOT NULL THEN 0 ELSE 1 END ASC,
     CASE WHEN Proximity IS NOT NULL THEN 0 ELSE 1 END ASC

Demo with your sample data.

So the most important order criteria is the first and the least important the last.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM