Scegliere la massima data tra 3 valori in T-SQL
In T-SQL di SQL Server non esiste una funzione che, passate 3 date presenti sulla stessa riga, restituisca la massima tra le 3.
Si può comunque raggiungere lo scopo con l'uso dell'istruzione CASE.
in questo modo abbiamo ottenuto la funzione MaxDate presente in altri linguaggi.
Si può ulteriormente affinare aggiungendo, nei risultati, anche la colonna scelta come massima data
da come risultato
con questi nuovi dati, se eseguiamo la query di prima otteniamo
a questo punto il risultato è corretto
Si può comunque raggiungere lo scopo con l'uso dell'istruzione CASE.
Dati di esempio
Per l'esempio uso questa tabella con 3 righe, ogni riga ha la data più alta in un campo differenteT-SQL: Tabella di esempio
CREATE TABLE [dbo].[TableDates](
[ID] [int] NOT NULL,
[DateA] [datetime2](7) NULL,
[DateB] [datetime2](7) NULL,
[DateC] [datetime2](7) NULL,
CONSTRAINT [PK_TableDates] PRIMARY KEY CLUSTERED ([ID] ASC)
);
INSERT INTO [dbo].[TableDates] VALUES(1, '2022-01-10', '2022-06-10', '2022-11-10');
INSERT INTO [dbo].[TableDates] VALUES(2, '2022-05-16', '2022-05-21', '2022-05-02');
INSERT INTO [dbo].[TableDates] VALUES(3, '2022-08-30', '2022-08-29', '2022-08-12');
MaxDate
Si può costruire una SELECT che tramite l'istruzione CASE ritorni la data massimaT-SQL: Max date
SELECT
CASE
WHEN [DateA] > [DateB] AND [DateA] > [DateC] THEN [DateA]
WHEN [DateB] > [DateA] AND [DateB] > [DateC] THEN [DateB]
ELSE [DateC]
END AS [MaxDate],
FROM [dbo].[TableDates]
Si può ulteriormente affinare aggiungendo, nei risultati, anche la colonna scelta come massima data
T-SQL: MaxDate con Choice
SELECT [ID], [DateA], [DateB], [DateC],
CASE
WHEN [DateA] > [DateB] AND [DateA] > [DateC] THEN [DateA]
WHEN [DateB] > [DateA] AND [DateB] > [DateC] THEN [DateB]
ELSE [DateC]
END AS [MaxDate],
CASE
WHEN [DateA] > [DateB] AND [DateA] > [DateC] THEN 'A'
WHEN [DateB] > [DateA] AND [DateB] > [DateC] THEN 'B'
ELSE 'C'
END AS [Choice]
FROM [dbo].[TableDates]
#class=table-striped ID;DateA;DateB;DateC;MaxDate;Choice 1;2022-01-10;2022-06-10;2022-11-10;2022-11-10;C 2;2022-05-16;2022-05-21;2022-05-02;2022-05-21;B 3;2022-08-30;2022-08-29;2022-08-12;2022-08-30;A
MaxDate con null
In molte situazioni può capitare di avere alcune date nulleT-SQL: Dati di esempio aggiuntivi
INSERT INTO [dbo].[TableDates] VALUES(10, '2022-01-10', '2022-06-10', null);
INSERT INTO [dbo].[TableDates] VALUES(20, '2022-05-16', null, '2022-05-02');
INSERT INTO [dbo].[TableDates] VALUES(30, null, '2022-08-29', '2022-08-12');
#class=table-striped ID;DateA;DateB;DateC;MaxDate;Choice 1;2022-01-10;2022-06-10;2022-11-10;2022-11-10;C 2;2022-05-16;2022-05-21;2022-05-02;2022-05-21;B 3;2022-08-30;2022-08-29;2022-08-12;2022-08-30;A 10;2022-01-10;2022-06-10;NULL;NULL;C 20;2022-05-16;NULL;2022-05-02;2022-05-02;C 30;NULL;2022-08-29;2022-08-12;2022-08-12;Cin pratica si finisce sempre nell'ELSE della CASE in quanto il confronto di maggioranza (>) con valori null fallisce.
Soluzione
Per far funzionare il confronto dobbiamo usare l'istruzione COALESCE(valore, dataMin) passando, come secondo parametro, una data che sarà sicuramente inferiore a quelle presenti nel dataset.T-SQL: MaxDate with null
DECLARE @minDate datetime2 = '1/1/1' -- considero che una delle date possa essere nulla
SELECT [ID], [DateA], [DateB], [DateC],
CASE
WHEN COALESCE([DateA], @minDate) > COALESCE([DateB], @minDate) AND COALESCE([DateA], @minDate) > COALESCE([DateC], @minDate) THEN [DateA]
WHEN COALESCE([DateB], @minDate) > COALESCE([DateA], @minDate) AND COALESCE([DateB], @minDate) > COALESCE([DateC], @minDate) THEN [DateB]
ELSE [DateC]
END AS [MaxDate],
CASE
WHEN COALESCE([DateA], @minDate) > COALESCE([DateB], @minDate) AND COALESCE([DateA], @minDate) > COALESCE([DateC], @minDate) THEN 'A'
WHEN COALESCE([DateB], @minDate) > COALESCE([DateA], @minDate) AND COALESCE([DateB], @minDate) > COALESCE([DateC], @minDate) THEN 'B'
ELSE 'C'
END AS [Choice]
FROM [dbo].[TableDates]
ID;DateA;DateB;DateC;MaxDate;Choice 1;2022-01-10;2022-06-10;2022-11-10;2022-11-10;C 2;2022-05-16;2022-05-21;2022-05-02;2022-05-21;B 3;2022-08-30;2022-08-29;2022-08-12;2022-08-30;A 10;2022-01-10;2022-06-10;NULL;2022-06-10;B 20;2022-05-16;NULL;2022-05-02;2022-05-16;A 30;NULL;2022-08-29;2022-08-12;2022-08-29;B