关于sql server:SQL MAX多列?

SQL MAX of multiple columns?

如何在几列的最大值的每一行中返回1值:

表名

1
[NUMBER, Date1, Date2, Date3, Cost]

我需要返回以下内容:

1
[NUMBER, Most_Recent_Date, Cost]

查询?


这是使用T-SQL和SQL Server的Max功能的另一个不错的解决方案

1
2
3
4
SELECT [Other FIELDS],
  (SELECT MAX(v)
   FROM (VALUES (date1), (date2), (date3),...) AS VALUE(v)) AS [MaxDate]
FROM [YourTableName]

好了,您可以使用CASE语句:

1
2
3
4
5
6
7
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

[对于Microsoft SQL Server 2008及更高版本,您可以在下面考虑Sven的简单答案。]


如果您使用的是MySQL,则可以使用

1
SELECT GREATEST(col1, col2 ...) FROM TABLE

还有3种方法,其中UNPIVOT(1)是迄今为止最快的,其次是Simulated Unpivot(3),它比(1)慢得多,但仍比(2)快

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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

解决方案1(UNPIVOT)

1
2
3
4
5
6
7
8
SELECT  NUMBER ,
        MAX(dDate) maxDate ,
        cost
FROM    dates UNPIVOT ( dDate FOR nDate IN ( Date1, Date2,
                                            Date3 ) ) AS u
GROUP BY NUMBER ,
        cost
GO

解决方案2(每行子查询)

1
2
3
4
5
6
7
8
9
10
11
12
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

解决方案3(模拟UNPIVOT)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
;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

以下两个示例中的任何一个都可以工作:

1
2
3
4
5
6
7
8
9
10
11
12
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

第二个是lassevk的答案的附件。

1
2
3
4
5
6
7
8
9
10
11
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

对于T-SQL(MSSQL 2008+)

1
2
3
4
5
6
7
8
9
SELECT
  (SELECT
     MAX(MyMaxName)
   FROM ( VALUES
            (MAX(Field1)),
            (MAX(Field2))
        ) MyAlias(MyMaxName)
  )
FROM MyTable1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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

标量函数会导致各种性能问题,因此最好将逻辑包装到内联表值函数中。这是我用来替换一些用户定义函数的函数,这些函数从最多十个日期的列表中选择了最小/最大日期。在我的100万行数据集上进行测试时,标量函数花费了15分钟以上的时间才杀死了该查询,而内联TVF花了1分钟的时间与将结果集选择到临时表中的时间相同。要使用此调用,请从SELECT中的子查询或CROSS APPLY中调用该函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
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)
)

1
2
3
4
5
6
SELECT
    CASE
        WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1
        WHEN Date2 >= Date3 THEN Date2
        ELSE Date3
    END AS MostRecentDate

这样写起来稍微容易些,因为按顺序评估case语句,所以跳过评估步骤。


不幸的是,拉瑟的答案虽然看似显而易见,但却存在严重缺陷。它不能处理NULL值。任何单个NULL值都会导致返回Date1。不幸的是,任何解决该问题的尝试都会变得非常混乱,并且不能很好地扩展到4个或更多的值。

databyss的第一个答案看起来(并且是)很好。但是,尚不清楚答案是否可以轻松地从多表联接中推断出3个值,而不是从单个表中推断出更简单的3个值。我想避免将这样的查询转换为子查询,只是为了获得最多3列,而且我很确定databyss的绝妙想法可以被清除。

因此,事不宜迟,这是我的解决方案(源自databyss的想法)。
它使用交叉联接选择常量来模拟多表联接的效果。需要注意的重要一点是,所有必要的别名都可以正确执行(并非总是如此),这可以使模式相当简单,并且可以通过其他列进行相当扩展。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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

问题:选择提供给实体的最低汇率
要求:代理商费率可以为空

1
2
3
4
5
6
7
8
9
10
11
[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

受到Nat的回答的启发


使用CROSS APPLY(适用于2005 +)....

1
2
3
SELECT MostRecentDate
FROM SourceTable
    CROSS APPLY (SELECT MAX(d) MostRecentDate FROM (VALUES (Date1), (Date2), (Date3)) AS a(d)) md

在SQL Server 2012中,我们可以使用IIF。

1
2
3
4
5
6
7
 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

如果使用的是SQL Server 2005,则可以使用UNPIVOT功能。这是一个完整的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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

请尝试使用UNPIVOT

1
2
3
4
5
6
SELECT MAX(MaxDt) MaxDt
   FROM tbl
UNPIVOT
   (MaxDt FOR E IN
      (Date1, Date2, Date3)
)AS unpvt;

我更喜欢基于案例的解决方案,当时我的假设是,与其他可能的解决方案(例如具有交叉应用,values(),自定义函数等的解决方案)相比,它对可能的性能下降的影响最小。

这是区分大小写的版本,用于处理大多数可能的测试用例的空值:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
;

结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

您可以创建一个传递日期的函数,然后将该函数添加到select语句中,如下所示。
选择数字,dbo.fxMost_Recent_Date(Date1,Date2,Date3),成本

1
CREATE FUNCTION  fxMost_Recent_Date

(
@ Date1 smalldatetime,
@ Date2 smalldatetime,
@ Date3 smalldatetime
)
返回smalldatetime

开始
声明@Result smalldatetime

1
2
3
4
5
6
7
8
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

结束


使用CASE WHEN的另一种方式

1
2
3
4
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

基于来自http://www.experts-exchange.com/Microsoft/Development/MS-SQL-Server/Q_24204894.html的ScottPletcher解决方案
我创建了一组函数(例如GetMaxOfDates3,GetMaxOfDates13),以使用UNION ALL查找最多13个日期值。
请参阅T-SQL函数以从同一行获取最大值
但是在编写这些功能时我还没有考虑过UNPIVOT解决方案


enter image description here上表是一个以薪金1,薪金2,薪金3,薪金4为列的员工薪水表。下面的查询将返回四列中的最大值

1
2
3
SELECT  
 (SELECT MAX(salval) FROM( VALUES (MAX(salary1)),(MAX(salary2)),(MAX(salary3)),(MAX(Salary4)))alias(salval)) AS largest_val
 FROM EmployeeSalary

在上面的查询中运行将输出为largest_val(10001)

以上查询的逻辑如下:

1
SELECT MAX(salvalue) FROM(VALUES (10001),(5098),(6070),(7500))alias(salvalue)

输出将是10001


这是一个很好的解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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

我不知道它是否在SQL上,等等...在M $ ACCESS帮助上,有一个叫做MAXA(Value1;Value2;...)的函数应该这样做。

希望可以帮助某人。

P.D .:值可以是列或计算得出的值,等等。


推荐阅读

    查询linux内存命令?

    查询linux内存命令?,系统,情况,信息,工具,电脑,状态,命令,内存,发行,总量,查

    linux查询ip命令?

    linux查询ip命令?,地址,网络,信息,设备,系统,电脑,终端,命令,中心,技术指标,l

    linux查询所有命令?

    linux查询所有命令?,工作,地址,系统,命令,信息,目录,工具,基础,文件,内容,lin

    linux日志命令查询?

    linux日志命令查询?,系统,名称,信息,实时,电脑,对比,最新,日志,命令,环境,Lin

    linux文本查询命令?

    linux文本查询命令?,标准,命令,文件,工具,数据,信息,位置,系统,内容,文本,Lin

    命令查询linux包安装?

    命令查询linux包安装?,软件,地方,地址,名字,系统,名称,信息,路径,命令,文件,

    查询linux的命令历史?

    查询linux的命令历史?,信息,系统,名称,地址,服务,命令,数据,环境,指令,用户,

    linux保存返回命令?

    linux保存返回命令?,档案,单位,时间,命令,权威,编辑,文件,音乐,内容,模式,mv

    linux线程查询命令?

    linux线程查询命令?,系统,第一,线程,命令,软件,名称,信息,进程,选项,方法,Lin

    linux终端返回命令行?

    linux终端返回命令行?,密码,状态,平台,系统,电脑,环境,认证,地址,终端,命令,

    linux命令左右查询?

    linux命令左右查询?,系统,信息,管理,地址,工作,命令,文件,单位,位置,数据,lin

    linux简单查询命令?

    linux简单查询命令?,地址,命令,信息,设备,电脑,系统,工作,文件,终端,内容,Lin

    linux终端返回命令行?

    linux终端返回命令行?,密码,状态,平台,系统,电脑,环境,认证,地址,终端,命令,

    linux保存返回命令?

    linux保存返回命令?,档案,单位,时间,命令,权威,编辑,文件,音乐,内容,模式,mv

    linux线程查询命令?

    linux线程查询命令?,系统,第一,线程,命令,软件,名称,信息,进程,选项,方法,Lin

    linux命令左右查询?

    linux命令左右查询?,系统,信息,管理,地址,工作,命令,文件,单位,位置,数据,lin

    linux简单查询命令?

    linux简单查询命令?,地址,命令,信息,设备,电脑,系统,工作,文件,终端,内容,Lin

    查询linux配置的命令?

    查询linux配置的命令?,系统,网络,地址,情况,信息,电脑,中科,状态,服务,命令,

    查询linux配置的命令?

    查询linux配置的命令?,系统,网络,地址,情况,信息,电脑,中科,状态,服务,命令,

    linux命令查询时间?

    linux命令查询时间?,时间,系统,状态,信息,数据,标准,地址,平台,环境,命令,在w