Sort by minimum value of two columns

后端 未结 13 1206
暖寄归人
暖寄归人 2021-02-03 17:13

I use SQL Server 2008 R2.

I need to sort a table by the minimal value of two columns.

The table looks like this:

ID: integer; 
Date         


        
相关标签:
13条回答
  • 2021-02-03 17:55

    This may be an alternate solution which does not require branching like CASE WHEN. This is based on the formula max(a,b)=1/2(a+b+|a−b|) as described here. We get the absolute values of a and b using DATEDIFF with a reference date ('1773-01-01').

    ORDER BY (DATEDIFF(d,'17730101' ,isnull(Startdate,enddate)) + DATEDIFF(d,'17730101' ,isnull(EndDate,Startdate)) 
        -  ABS(DATEDIFF(d,isnull(Startdate,enddate),isnull(EndDate,Startdate))))
    

    Test Data

    Create Table #DateData(ID int Identity, Name varchar(15),Startdate datetime,EndDate DateTime)
    Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 18:48:27','2015-04-18 18:48:27')
    Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-19 18:48:27','2015-04-18 18:48:27')
    Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-20 18:48:27','2015-04-18 18:48:27')
    Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-11 18:48:27','2015-04-22 18:48:27')
    Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-05-09 18:48:27','2015-04-18 18:48:27')
    Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 19:07:38','2015-04-17 18:55:38')
    Insert Into #DateData(Name,Startdate,EndDate) values ('myName','2015-04-17 19:07:38','2015-05-12 18:56:29')
    

    Complete Query

    select *
    from #DateData order by (DATEDIFF(d,'17730101' ,isnull(Startdate,enddate)) + DATEDIFF(d,'17730101' ,isnull(EndDate,Startdate)) 
    -  ABS(DATEDIFF(d,isnull(Startdate,enddate),isnull(EndDate,Startdate))))
    
    0 讨论(0)
  • 2021-02-03 17:56

    Code for max

    I'm using CROSS APPLY, I am not sure about the performance, But CROSS APPLY often has a better performance in my experience.

    CREATE TABLE #Test (ID INT, Date1 DATETIME, Date2 DATETIME)
    INSERT INTO #Test SELECT 1, NULL, '1/1/1';INSERT INTO #Test SELECT 2, NULL, NULL;INSERT INTO #Test SELECT 3, '2/2/2', '3/3/1';INSERT INTO #Test SELECT 4, '3/3/3', '11/1/1'
    
    SELECT t.ID, Date1, Date2, MinDate
    FROM #TEST t
        CROSS APPLY (SELECT MIN(d) MinDate FROM (VALUES (Date1), (Date2)) AS a(d)) md
    ORDER BY MinDate
    
    DROP TABLE #Test
    
    0 讨论(0)
  • 2021-02-03 17:56

    I'd shift focus from how to do this to why you need this - and propose to change the schema instead. The rule of thumb is: if you need to pull stunts to access your data, there is a bad design decision.

    As you've seen, this task is very untypical for SQL so, though it's possible, all the proposed methods are painfully slow in comparison to an ordinary ORDER BY.

    • If you need to do this often then the minimum of the two dates must have some independent physical meaning for your application.
      • Which justifies a separate column (or maybe a column replacing one of the two) - maintained by a trigger or even manually if the meaning is independent enough for the column to possibly be neither in some cases.
    0 讨论(0)
  • 2021-02-03 17:59

    You can use min function in order by clause:

    select * 
    from [table] d
    order by ( select min(q.t) from (
               select d.date1 t union select d.date2) q
             )
    

    You can also use case statement in order by clause but as you know the result of comparing (> and <) any value (null or none null) with null is not true even if you have setted ansi_nulls to off. so for guaranteeing the sort you wanted, you need to handle nulls, as you know in case clause if the result of a when is true then further when statements are not evaluated so you can say:

    select * from [table]
    order by case 
               when date1 is null then date2
               when date2 is null then date1 
               when date1<date2 then date1 -- surely date1 and date2 are not null here
               else date2 
             end
    

    Also here are some other solutions if your scenario be different maybe maybe you evaluate the result of comparing multiple columns(or a calculation) inside a separated field and finally order by that calculated field without using any condition inside your order by clause.

    0 讨论(0)
  • 2021-02-03 18:00

    NOT NULL columns. You need to add CASE statement into ORDER BY clause in following:

    SELECT Id, Date1, Date2
    FROM YourTable
    ORDER BY CASE 
               WHEN Date1 < Date2 THEN Date1 
               ELSE Date2 
             END 
    

    NULLABLE columns. As Zohar Peled wrote in comments if columns are nullable you could use ISNULL (but better to use COALESCE instead of ISNULL, because It's ANSI SQL standard) in following:

    SELECT Id, Date1, Date2
    FROM YourTable
    ORDER BY CASE 
               WHEN COALESCE(Date1, '1753-01-01') < COALESCE(Date2, '1753-01-01') THEN Date1 
               ELSE Date2 
             END
    

    You can read about ANSI standard dateformat 1753-01-01 here.

    0 讨论(0)
  • 2021-02-03 18:03

    Use a CASE expression in the ORDER BY:

     ORDER BY case when date1 < date2 then date1 else date2 end
    

    Edit:

    If null values need to be considered, add coalesce():

     ORDER BY case when date1 < date2 then date1 else coalesce(date2,date1) end
    

    Explanation:

    If date1 < date2 then order by date1. (Both dates are non null here.) Works just like before.

    Else use COALESCE() to order by date2 (when date2 is not null), or date1 (when date2 is null), or by null (if both dates are null.)

    0 讨论(0)
提交回复
热议问题