[英]SQL MAX of multiple columns?
How do you return 1 value per row of the max of several columns:如何在几列的最大值中每行返回 1 个值:
TableName表名
[Number, Date1, Date2, Date3, Cost]
I need to return something like this:我需要返回这样的东西:
[Number, Most_Recent_Date, Cost]
Query?询问?
Here is another nice solution for the Max
functionality using T-SQL and SQL Server这是使用 T-SQL 和 SQL Server 的
Max
功能的另一个不错的解决方案
SELECT [Other Fields],
(SELECT Max(v)
FROM (VALUES (date1), (date2), (date3),...) AS value(v)) as [MaxDate]
FROM [YourTableName]
Values is the Table Value Constructor . Values 是表值构造函数。
"Specifies a set of row value expressions to be constructed into a table. The Transact-SQL table value constructor allows multiple rows of data to be specified in a single DML statement. The table value constructor can be specified either as the VALUES clause of an INSERT ... VALUES statement, or as a derived table in either the USING clause of the MERGE statement or the FROM clause." "指定要构造到表中的一组行值表达式。Transact-SQL 表值构造函数允许在单个 DML 语句中指定多行数据。表值构造函数可以指定为INSERT ... VALUES 语句,或作为 MERGE 语句的 USING 子句或 FROM 子句中的派生表。”
This is an old answer and broken in many way.这是一个古老的答案,并且在很多方面都被打破了。
See https://stackoverflow.com/a/6871572/194653 which has way more upvotes and works with sql server 2008+ and handles nulls, etc.请参阅https://stackoverflow.com/a/6871572/194653 ,它有更多的赞成票,可与 sql server 2008+ 一起使用并处理空值等。
Original but problematic answer :原始但有问题的答案:
Well, you can use the CASE statement:好吧,您可以使用 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
如果您使用的是 MySQL,则可以使用
SELECT GREATEST(col1, col2 ...) FROM table
There are 3 more methods where UNPIVOT
(1) is the fastest by far, followed by Simulated Unpivot (3) which is much slower than (1) but still faster than (2)还有 3 种方法,其中
UNPIVOT
(1) 是迄今为止最快的,其次是 Simulated Unpivot (3),它比 (1) 慢得多但仍然比 (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
)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
)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
Either of the two samples below will work:以下两个示例中的任何一个都可以使用:
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
The second is an add-on to lassevk's answer.第二个是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
For T-SQL (MSSQL 2008+)对于 T-SQL (MSSQL 2008+)
SELECT
(SELECT
MAX(MyMaxName)
FROM ( VALUES
(MAX(Field1)),
(MAX(Field2))
) MyAlias(MyMaxName)
)
FROM MyTable1
Scalar Function cause all sorts of performance issues, so its better to wrap the logic into an Inline Table Valued Function if possible.标量函数会导致各种性能问题,因此如果可能,最好将逻辑包装到内联表值函数中。 This is the function I used to replace some User Defined Functions which selected the Min/Max dates from a list of upto ten dates.
这是我用来替换一些用户定义函数的函数,这些函数从最多十个日期的列表中选择最小/最大日期。 When tested on my dataset of 1 Million rows the Scalar Function took over 15 minutes before I killed the query the Inline TVF took 1 minute which is the same amount of time as selecting the resultset into a temporary table.
在我的 100 万行数据集上进行测试时,标量函数在我终止查询之前花费了 15 多分钟,而内联 TVF 花费了 1 分钟,这与将结果集选择到临时表中的时间相同。 To use this call the function from either a subquery in the the SELECT or a CROSS APPLY.
要使用此调用,请从 SELECT 或 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)
)
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
SELECT
CASE
WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
WHEN Date2 >= Date3 THEN Date2
ELSE Date3
END AS MostRecentDate
This is slightly easier to write out and skips evaluation steps as the case statement is evaluated in order.由于 case 语句是按顺序计算的,所以写出来会稍微容易一些,并且会跳过计算步骤。
Unfortunately Lasse's answer , though seemingly obvious, has a crucial flaw.不幸的是, Lasse 的回答虽然看起来很明显,但有一个关键的缺陷。 It cannot handle NULL values.
它无法处理 NULL 值。 Any single NULL value results in Date1 being returned.
任何单个 NULL 值都会导致 Date1 被返回。 Unfortunately any attempt to fix that problem tends to get extremely messy and doesn't scale to 4 or more values very nicely.
不幸的是,任何解决该问题的尝试都会变得非常混乱,并且不能很好地扩展到 4 个或更多值。
databyss's first answer looked (and is) good. databyss 的第一个答案看起来(而且现在)很好。 However, it wasn't clear whether the answer would easily extrapolate to 3 values from a multi-table join instead of the simpler 3 values from a single table.
但是,不清楚该答案是否可以轻松地从多表连接中推断出 3 个值,而不是从单个表中推断出更简单的 3 个值。 I wanted to avoid turning such a query into a sub-query just to get the max of 3 columns, also I was pretty sure databyss's excellent idea could be cleaned up a bit.
我想避免将这样的查询变成子查询,只是为了获得最多 3 列,而且我很确定 databyss 的好主意可以稍微清理一下。
So without further ado, here's my solution (derived from databyss's idea).所以不用多说,这是我的解决方案(源自databyss的想法)。
It uses cross-joins selecting constants to simulate the effect of a multi-table join.它使用交叉连接选择常量来模拟多表连接的效果。 The important thing to note is that all the necessary aliases carry through correctly (which is not always the case) and this keeps the pattern quite simple and fairly scalable through additional columns.
需要注意的重要一点是,所有必要的别名都正确执行(情况并非总是如此),这使模式非常简单,并且通过附加列具有相当的可扩展性。
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
Problem: choose the minimum rate value given to an entity Requirements: Agency rates can be null问题:选择给予实体的最低费率值要求:代理费率可以为空
[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
Inspired by this answer from Nat灵感来自Nat的这个答案
Using CROSS APPLY (for 2005+) ....使用 CROSS APPLY(适用于 2005+)....
SELECT MostRecentDate
FROM SourceTable
CROSS APPLY (SELECT MAX(d) MostRecentDate FROM (VALUES (Date1), (Date2), (Date3)) AS a(d)) md
If you are using SQL Server 2005, you can use the UNPIVOT feature.如果您使用的是 SQL Server 2005,则可以使用 UNPIVOT 功能。 Here is a complete example:
这是一个完整的例子:
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
Please try using UNPIVOT
:请尝试使用
UNPIVOT
:
SELECT MAX(MaxDt) MaxDt
FROM tbl
UNPIVOT
(MaxDt FOR E IN
(Date1, Date2, Date3)
)AS unpvt;
I prefer solutions based on case-when, my assumption is that it should have the least impact on possible performance drop compared to other possible solutions like those with cross-apply, values(), custom functions etc.我更喜欢基于 case-when 的解决方案,我的假设是,与其他可能的解决方案(例如交叉应用、values()、自定义函数等)相比,它对可能的性能下降的影响应该最小。
Here is the case-when version that handles null values with most of possible test cases:这是使用大多数可能的测试用例处理空值的版本:
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
;
and the result is:结果是:
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
Based on the ScottPletcher 's solution from http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_24204894.html I've created a set of functions (eg GetMaxOfDates3 , GetMaxOfDates13 )to find max of up to 13 Date values using UNION ALL.基于来自http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_24204894.html的ScottPletcher的解决方案,我创建了一组函数(例如 GetMaxOfDates3 、 GetMaxOfDates13 )来查找最大值使用 UNION ALL 最多 13 个日期值。 See T-SQL function to Get Maximum of values from the same row However I haven't considered UNPIVOT solution at the time of writing these functions
请参阅T-SQL 函数以从同一行获取最大值但是在编写这些函数时我还没有考虑 UNPIVOT 解决方案
CREATE FUNCTION GetMaxOfDates13 (
@value01 DateTime = NULL,
@value02 DateTime = NULL,
@value03 DateTime = NULL,
@value04 DateTime = NULL,
@value05 DateTime = NULL,
@value06 DateTime = NULL,
@value07 DateTime = NULL,
@value08 DateTime = NULL,
@value09 DateTime = NULL,
@value10 DateTime = NULL,
@value11 DateTime = NULL,
@value12 DateTime = NULL,
@value13 DateTime = NULL
)
RETURNS DateTime
AS
BEGIN
RETURN (
SELECT TOP 1 value
FROM (
SELECT @value01 AS value UNION ALL
SELECT @value02 UNION ALL
SELECT @value03 UNION ALL
SELECT @value04 UNION ALL
SELECT @value05 UNION ALL
SELECT @value06 UNION ALL
SELECT @value07 UNION ALL
SELECT @value08 UNION ALL
SELECT @value09 UNION ALL
SELECT @value10 UNION ALL
SELECT @value11 UNION ALL
SELECT @value12 UNION ALL
SELECT @value13
) AS [values]
ORDER BY value DESC
)
END –FUNCTION
GO
CREATE FUNCTION GetMaxOfDates3 (
@value01 DateTime = NULL,
@value02 DateTime = NULL,
@value03 DateTime = NULL
)
RETURNS DateTime
AS
BEGIN
RETURN dbo.GetMaxOfDates13(@value01,@value02,@value03,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL)
END –FUNCTION
Finally, for the following:最后,针对以下内容:
we can use GREATEST , too.我们也可以使用GREATEST 。 Similar to other T-SQL functions, here are few important notes:
与其他 T-SQL 函数类似,这里有几个重要的注意事项:
The following types are not supported for comparison in GREATEST: varchar(max), varbinary(max) or nvarchar(max) exceeding 8,000 bytes, cursor, geometry, geography, image, non-byte-ordered user-defined types, ntext, table, text, and xml. GREATEST 中不支持以下类型进行比较:varchar(max)、varbinary(max) 或 nvarchar(max) 超过 8,000 字节、cursor、geometry、geography、image、非字节排序的用户定义类型、ntext、table 、文本和 xml。
You could create a function where you pass the dates and then add the function to the select statement like below.您可以创建一个函数,在其中传递日期,然后将该函数添加到 select 语句中,如下所示。 select Number, dbo.fxMost_Recent_Date(Date1,Date2,Date3), Cost
选择数字、dbo.fxMost_Recent_Date(Date1,Date2,Date3)、成本
create FUNCTION fxMost_Recent_Date
( @Date1 smalldatetime, @Date2 smalldatetime, @Date3 smalldatetime ) RETURNS smalldatetime AS BEGIN DECLARE @Result smalldatetime (@Date1 smalldatetime, @Date2 smalldatetime, @Date3 smalldatetime ) RETURNS smalldatetime AS BEGIN 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
END结尾
Another way to use CASE WHEN另一种使用CASE WHEN 的方法
SELECT CASE true
WHEN max(row1) >= max(row2) THEN CASE true WHEN max(row1) >= max(row3) THEN max(row1) ELSE max(row3) end ELSE
CASE true WHEN max(row2) >= max(row3) THEN max(row2) ELSE max(row3) END END
FROM yourTable
I have a table called TblItem if I want to get the biggest Id. 如果我想获取最大的ID,则有一个名为TblItem的表。 I use the following code.
我使用以下代码。
select MAX(Id) from TblItem
My solution can handle null value comparison as well.我的解决方案也可以处理空值比较。 It can be simplified by writing as one single query but for an explanation, I am using CTE.
可以通过编写单个查询来简化它,但为了解释,我使用的是 CTE。 The idea is to reduce the comparison from 3 number to 2 number in step 1 and then from 2 number to 1 number in step 2.
这个想法是在步骤 1 中将比较从 3 个数字减少到 2 个数字,然后在步骤 2 中将比较从 2 个数字减少到 1 个数字。
with x1 as
(
select 1 as N1, null as N2, 3 as N3
union
select 1 as N1, null as N2, null as N3
union
select null as N1, null as N2, null as N3
)
,x2 as
(
select
N1,N2,N3,
IIF(Isnull(N1,0)>=Isnull(N2,0),N1,N2) as max1,
IIF(Isnull(N2,0)>=Isnull(N3,0),N2,N3) as max2
from x1
)
,x3 as
(
select N1,N2,N3,max1,max2,
IIF(IsNull(max1,0)>=IsNull(max2,0),max1,max2) as MaxNo
from x2
)
select * from x3
Output:输出:
here is a good 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
I do not know if it is on SQL, etc... on M$ACCESS help there is a function called MAXA(Value1;Value2;...)
that is supposed to do such.我不知道它是否在 SQL 等上...在 M$ACCESS 帮助中有一个名为
MAXA(Value1;Value2;...)
函数应该这样做。
Hope can help someone.希望可以帮助某人。
PD: Values can be columns or calculated ones, etc. PD:值可以是列或计算值等。
Above table is an employee salary table with salary1,salary2,salary3,salary4 as columns.Query below will return the max value out of four columns
上表是一个员工工资表,以salary1、salary2、salary3、salary4为列。下面的查询将返回四列中的最大值
select
(select Max(salval) from( values (max(salary1)),(max(salary2)),(max(salary3)),(max(Salary4)))alias(salval)) as largest_val
from EmployeeSalary
Running above query will give output as largest_val(10001)运行上面的查询将输出为 large_val(10001)
Logic of above query is as below:上述查询的逻辑如下:
select Max(salvalue) from(values (10001),(5098),(6070),(7500))alias(salvalue)
output will be 10001输出将是 10001
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.