Réponses:
Eh bien, vous pouvez utiliser l'instruction CASE:
SELECT
CASE
WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
WHEN Date2 >= Date1 AND Date2 >= Date3 THEN Date2
WHEN Date3 >= Date1 AND Date3 >= Date2 THEN Date3
ELSE Date1
END AS MostRecentDate
[Pour Microsoft SQL Server 2008 et supérieur, vous pouvez envisager la réponse plus simple de Sven ci-dessous.]
Voici une autre belle solution pour la Max
fonctionnalité utilisant T-SQL et SQL Server
SELECT [Other Fields],
(SELECT Max(v)
FROM (VALUES (date1), (date2), (date3),...) AS value(v)) as [MaxDate]
FROM [YourTableName]
Si vous utilisez MySQL, vous pouvez utiliser
SELECT GREATEST(col1, col2 ...) FROM table
Il y a 3 autres méthodes où UNPIVOT
(1) est de loin le plus rapide, suivi de Simulated Unpivot (3) qui est beaucoup plus lent que (1) mais toujours plus rapide que (2)
CREATE TABLE dates
(
number INT PRIMARY KEY ,
date1 DATETIME ,
date2 DATETIME ,
date3 DATETIME ,
cost INT
)
INSERT INTO dates
VALUES ( 1, '1/1/2008', '2/4/2008', '3/1/2008', 10 )
INSERT INTO dates
VALUES ( 2, '1/2/2008', '2/3/2008', '3/3/2008', 20 )
INSERT INTO dates
VALUES ( 3, '1/3/2008', '2/2/2008', '3/2/2008', 30 )
INSERT INTO dates
VALUES ( 4, '1/4/2008', '2/1/2008', '3/4/2008', 40 )
GO
UNPIVOT
)SELECT number ,
MAX(dDate) maxDate ,
cost
FROM dates UNPIVOT ( dDate FOR nDate IN ( Date1, Date2,
Date3 ) ) as u
GROUP BY number ,
cost
GO
SELECT number ,
( SELECT MAX(dDate) maxDate
FROM ( SELECT d.date1 AS dDate
UNION
SELECT d.date2
UNION
SELECT d.date3
) a
) MaxDate ,
Cost
FROM dates d
GO
UNPIVOT
);WITH maxD
AS ( SELECT number ,
MAX(CASE rn
WHEN 1 THEN Date1
WHEN 2 THEN date2
ELSE date3
END) AS maxDate
FROM dates a
CROSS JOIN ( SELECT 1 AS rn
UNION
SELECT 2
UNION
SELECT 3
) b
GROUP BY Number
)
SELECT dates.number ,
maxD.maxDate ,
dates.cost
FROM dates
INNER JOIN MaxD ON dates.number = maxD.number
GO
DROP TABLE dates
GO
L'un des deux exemples ci-dessous fonctionnera:
SELECT MAX(date_columns) AS max_date
FROM ( (SELECT date1 AS date_columns
FROM data_table )
UNION
( SELECT date2 AS date_columns
FROM data_table
)
UNION
( SELECT date3 AS date_columns
FROM data_table
)
) AS date_query
Le second est un complément à la réponse de Lassevk .
SELECT MAX(MostRecentDate)
FROM ( SELECT CASE WHEN date1 >= date2
AND date1 >= date3 THEN date1
WHEN date2 >= date1
AND date2 >= date3 THEN date2
WHEN date3 >= date1
AND date3 >= date2 THEN date3
ELSE date1
END AS MostRecentDate
FROM data_table
) AS date_query
DECLARE @TableName TABLE (Number INT, Date1 DATETIME, Date2 DATETIME, Date3 DATETIME, Cost MONEY)
INSERT INTO @TableName
SELECT 1, '20000101', '20010101','20020101',100 UNION ALL
SELECT 2, '20000101', '19900101','19980101',99
SELECT Number,
Cost ,
(SELECT MAX([Date])
FROM (SELECT Date1 AS [Date]
UNION ALL
SELECT Date2
UNION ALL
SELECT Date3
)
D
)
[Most Recent Date]
FROM @TableName
La fonction scalaire provoque toutes sortes de problèmes de performances, il est donc préférable d'envelopper la logique dans une fonction à valeur de table en ligne si possible. C'est la fonction que j'ai utilisée pour remplacer certaines fonctions définies par l'utilisateur qui sélectionnaient les dates Min / Max dans une liste de jusqu'à dix dates. Lorsqu'elle a été testée sur mon ensemble de données de 1 million de lignes, la fonction scalaire a pris plus de 15 minutes avant de tuer la requête. Le TVF en ligne a pris 1 minute, ce qui équivaut à la sélection de l'ensemble de résultats dans une table temporaire. Pour utiliser cet appel, la fonction à partir d'une sous-requête dans le SELECT ou un CROSS APPLY.
CREATE FUNCTION dbo.Get_Min_Max_Date
(
@Date1 datetime,
@Date2 datetime,
@Date3 datetime,
@Date4 datetime,
@Date5 datetime,
@Date6 datetime,
@Date7 datetime,
@Date8 datetime,
@Date9 datetime,
@Date10 datetime
)
RETURNS TABLE
AS
RETURN
(
SELECT Max(DateValue) Max_Date,
Min(DateValue) Min_Date
FROM (
VALUES (@Date1),
(@Date2),
(@Date3),
(@Date4),
(@Date5),
(@Date6),
(@Date7),
(@Date8),
(@Date9),
(@Date10)
) AS Dates(DateValue)
)
SELECT
CASE
WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
WHEN Date2 >= Date3 THEN Date2
ELSE Date3
END AS MostRecentDate
Ceci est légèrement plus facile à écrire et ignore les étapes d'évaluation car l'instruction de cas est évaluée dans l'ordre.
Malheureusement, la réponse de Lasse , bien qu'apparemment évidente, a un défaut crucial. Il ne peut pas gérer les valeurs NULL. Toute valeur NULL unique entraîne le renvoi de Date1. Malheureusement, toute tentative de résoudre ce problème a tendance à devenir extrêmement compliquée et ne se transforme pas très bien en 4 valeurs ou plus.
La première réponse de databyss semblait (et est) bonne. Cependant, il n'était pas clair si la réponse serait facilement extrapolable à 3 valeurs à partir d'une jointure multi-table au lieu des 3 valeurs plus simples d'une table unique. Je voulais éviter de transformer une telle requête en sous-requête juste pour obtenir le maximum de 3 colonnes, j'étais également sûr que l'excellente idée de databyss pouvait être nettoyée un peu.
Alors sans plus tarder, voici ma solution (dérivée de l'idée de databyss).
Il utilise des constantes de sélection de jointures croisées pour simuler l'effet d'une jointure multi-tables. La chose importante à noter est que tous les alias nécessaires s'exécutent correctement (ce qui n'est pas toujours le cas) et cela maintient le modèle assez simple et assez évolutif à travers des colonnes supplémentaires.
DECLARE @v1 INT ,
@v2 INT ,
@v3 INT
--SET @v1 = 1 --Comment out SET statements to experiment with
--various combinations of NULL values
SET @v2 = 2
SET @v3 = 3
SELECT ( SELECT MAX(Vals)
FROM ( SELECT v1 AS Vals
UNION
SELECT v2
UNION
SELECT v3
) tmp
WHERE Vals IS NOT NULL -- This eliminates NULL warning
) AS MaxVal
FROM ( SELECT @v1 AS v1
) t1
CROSS JOIN ( SELECT @v2 AS v2
) t2
CROSS JOIN ( SELECT @v3 AS v3
) t3
Problème: choisissez la valeur de taux minimum donnée à une entité Exigences: Les taux d'agence peuvent être nuls
[MinRateValue] =
CASE
WHEN ISNULL(FitchRating.RatingValue, 100) < = ISNULL(MoodyRating.RatingValue, 99)
AND ISNULL(FitchRating.RatingValue, 100) < = ISNULL(StandardPoorsRating.RatingValue, 99)
THEN FitchgAgency.RatingAgencyName
WHEN ISNULL(MoodyRating.RatingValue, 100) < = ISNULL(StandardPoorsRating.RatingValue , 99)
THEN MoodyAgency.RatingAgencyName
ELSE ISNULL(StandardPoorsRating.RatingValue, 'N/A')
END
Inspiré par cette réponse de Nat
Si vous utilisez SQL Server 2005, vous pouvez utiliser la fonctionnalité UNPIVOT. Voici un exemple complet:
create table dates
(
number int,
date1 datetime,
date2 datetime,
date3 datetime
)
insert into dates values (1, '1/1/2008', '2/4/2008', '3/1/2008')
insert into dates values (1, '1/2/2008', '2/3/2008', '3/3/2008')
insert into dates values (1, '1/3/2008', '2/2/2008', '3/2/2008')
insert into dates values (1, '1/4/2008', '2/1/2008', '3/4/2008')
select max(dateMaxes)
from (
select
(select max(date1) from dates) date1max,
(select max(date2) from dates) date2max,
(select max(date3) from dates) date3max
) myTable
unpivot (dateMaxes For fieldName In (date1max, date2max, date3max)) as tblPivot
drop table dates
Utilisation de CROSS APPLY (pour 2005+) ....
SELECT MostRecentDate
FROM SourceTable
CROSS APPLY (SELECT MAX(d) MostRecentDate FROM (VALUES (Date1), (Date2), (Date3)) AS a(d)) md
À partir de SQL Server 2012, nous pouvons utiliser IIF .
DECLARE @Date1 DATE='2014-07-03';
DECLARE @Date2 DATE='2014-07-04';
DECLARE @Date3 DATE='2014-07-05';
SELECT IIF(@Date1>@Date2,
IIF(@Date1>@Date3,@Date1,@Date3),
IIF(@Date2>@Date3,@Date2,@Date3)) AS MostRecentDate
DECLARE @Date1 DATE='2014-08-01'; DECLARE @Date2 DATE=null; DECLARE @Date3 DATE='2014-07-05'; /*this gets returned*/
select IIF(@Date1 > @Date2 or @Date2 is null, IIF(@Date1 > @Date3 or @Date3 is null, @Date1, @Date3), IIF(@Date2 > @Date3 or @Date3 is null, @Date2, @Date3)) as MostRecentDate
Je préfère les solutions basées sur le cas où, mon hypothèse est que cela devrait avoir le moins d'impact sur la baisse de performance possible par rapport à d'autres solutions possibles comme celles avec application croisée, valeurs (), fonctions personnalisées, etc.
Voici la version au cas où qui gère les valeurs nulles avec la plupart des cas de test possibles:
SELECT
CASE
WHEN Date1 > coalesce(Date2,'0001-01-01') AND Date1 > coalesce(Date3,'0001-01-01') THEN Date1
WHEN Date2 > coalesce(Date3,'0001-01-01') THEN Date2
ELSE Date3
END AS MostRecentDate
, *
from
(values
( 1, cast('2001-01-01' as Date), cast('2002-01-01' as Date), cast('2003-01-01' as Date))
,( 2, cast('2001-01-01' as Date), cast('2003-01-01' as Date), cast('2002-01-01' as Date))
,( 3, cast('2002-01-01' as Date), cast('2001-01-01' as Date), cast('2003-01-01' as Date))
,( 4, cast('2002-01-01' as Date), cast('2003-01-01' as Date), cast('2001-01-01' as Date))
,( 5, cast('2003-01-01' as Date), cast('2001-01-01' as Date), cast('2002-01-01' as Date))
,( 6, cast('2003-01-01' as Date), cast('2002-01-01' as Date), cast('2001-01-01' as Date))
,( 11, cast(NULL as Date), cast('2002-01-01' as Date), cast('2003-01-01' as Date))
,( 12, cast(NULL as Date), cast('2003-01-01' as Date), cast('2002-01-01' as Date))
,( 13, cast('2003-01-01' as Date), cast(NULL as Date), cast('2002-01-01' as Date))
,( 14, cast('2002-01-01' as Date), cast(NULL as Date), cast('2003-01-01' as Date))
,( 15, cast('2003-01-01' as Date), cast('2002-01-01' as Date), cast(NULL as Date))
,( 16, cast('2002-01-01' as Date), cast('2003-01-01' as Date), cast(NULL as Date))
,( 21, cast('2003-01-01' as Date), cast(NULL as Date), cast(NULL as Date))
,( 22, cast(NULL as Date), cast('2003-01-01' as Date), cast(NULL as Date))
,( 23, cast(NULL as Date), cast(NULL as Date), cast('2003-01-01' as Date))
,( 31, cast(NULL as Date), cast(NULL as Date), cast(NULL as Date))
) as demoValues(id, Date1,Date2,Date3)
order by id
;
et le résultat est:
MostRecent id Date1 Date2 Date3
2003-01-01 1 2001-01-01 2002-01-01 2003-01-01
2003-01-01 2 2001-01-01 2003-01-01 2002-01-01
2003-01-01 3 2002-01-01 2001-01-01 2002-01-01
2003-01-01 4 2002-01-01 2003-01-01 2001-01-01
2003-01-01 5 2003-01-01 2001-01-01 2002-01-01
2003-01-01 6 2003-01-01 2002-01-01 2001-01-01
2003-01-01 11 NULL 2002-01-01 2003-01-01
2003-01-01 12 NULL 2003-01-01 2002-01-01
2003-01-01 13 2003-01-01 NULL 2002-01-01
2003-01-01 14 2002-01-01 NULL 2003-01-01
2003-01-01 15 2003-01-01 2002-01-01 NULL
2003-01-01 16 2002-01-01 2003-01-01 NULL
2003-01-01 21 2003-01-01 NULL NULL
2003-01-01 22 NULL 2003-01-01 NULL
2003-01-01 23 NULL NULL 2003-01-01
NULL 31 NULL NULL NULL
Vous pouvez créer une fonction où vous passez les dates, puis ajouter la fonction à l'instruction select comme ci-dessous. sélectionnez Number, dbo.fxMost_Recent_Date (Date1, Date2, Date3), Cost
create FUNCTION fxMost_Recent_Date
(@ Date1 smalldatetime, @ Date2 smalldatetime, @ Date3 smalldatetime) RETOURNE smalldatetime COMME COMMENCER DECLARE @Result smalldatetime
declare @MostRecent smalldatetime
set @MostRecent='1/1/1900'
if @Date1>@MostRecent begin set @MostRecent=@Date1 end
if @Date2>@MostRecent begin set @MostRecent=@Date2 end
if @Date3>@MostRecent begin set @MostRecent=@Date3 end
RETURN @MostRecent
FIN
Basé sur la solution ScottPletcher de http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_24204894.html, j'ai créé un ensemble de fonctions (par exemple GetMaxOfDates3, GetMaxOfDates13) pour trouver max jusqu'à 13 valeurs de date en utilisant UNION ALL. Voir la fonction T-SQL pour obtenir le maximum de valeurs de la même ligne. Cependant, je n'ai pas envisagé la solution UNPIVOT au moment d'écrire ces fonctions
Le tableau ci-dessus est un tableau des salaires des employés avec salaire1, salaire2, salaire3, salaire4 sous forme de colonnes.La requête ci-dessous renverra la valeur maximale sur quatre colonnes
select
(select Max(salval) from( values (max(salary1)),(max(salary2)),(max(salary3)),(max(Salary4)))alias(salval)) as largest_val
from EmployeeSalary
L'exécution de la requête ci-dessus donnera la sortie comme la plus grande_val (10001)
La logique de la requête ci-dessus est la suivante:
select Max(salvalue) from(values (10001),(5098),(6070),(7500))alias(salvalue)
la sortie sera 10001
voici une bonne solution:
CREATE function [dbo].[inLineMax] (@v1 float,@v2 float,@v3 float,@v4 float)
returns float
as
begin
declare @val float
set @val = 0
declare @TableVal table
(value float )
insert into @TableVal select @v1
insert into @TableVal select @v2
insert into @TableVal select @v3
insert into @TableVal select @v4
select @val= max(value) from @TableVal
return @val
end
Je ne sais pas si c'est sur SQL, etc ... sur l'aide M $ ACCESS il y a une fonction appelée MAXA(Value1;Value2;...)
qui est censée faire ça.
L'espoir peut aider quelqu'un.
PD: Les valeurs peuvent être des colonnes ou des valeurs calculées, etc.
MAXA
est une fonction Excel , pas Access.
WHEN Date1 > Date2 AND Date1 > Date3 THEN Date1; WHEN Date2 > Date3 THEN Date3; ELSE Date3
?