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.
Dati di esempio
Per l'esempio uso questa tabella con 3 righe, ogni riga ha la data più alta in un campo differente
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 massima
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]
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
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]
da come risultato
#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
nulleINSERT 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');
con questi nuovi dati, se eseguiamo la query di prima otteniamo
#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;C
in 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.
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]
a questo punto il risultato è
corretto
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