多列的SQL MAX?

Ben*_*enB 343 sql t-sql sql-server

如何在每行最多的几列中返回1个值:

表名

[Number, Date1, Date2, Date3, Cost]
Run Code Online (Sandbox Code Playgroud)

我需要返回这样的东西:

[Number, Most_Recent_Date, Cost]
Run Code Online (Sandbox Code Playgroud)

查询?

Sve*_*ven 809

这是Max使用T-SQL和SQL Server的另一个很好的解决方案

SELECT [Other Fields],
  (SELECT Max(v) 
   FROM (VALUES (date1), (date2), (date3),...) AS value(v)) as [MaxDate]
FROM [YourTableName]
Run Code Online (Sandbox Code Playgroud)

  • SQL版本必须> = 2008. (46认同)
  • 我最初也不理解VALUE(v).如果您想了解VALUE,请尝试创建虚拟1列表的查询:SELECT*FROM(VALUES(1),(5),(1))as listOfValues(columnName)此查询创建虚拟2​​列表: SELECT*FROM(VALUES(1,2),(5,3),(1,4))as tableOfValues(columnName1,ColumnName2)现在您可以理解为什么该示例查询中包含AS值(v).我的最终查询如下所示:SELECT Max(currentValues)as Max FROM(VALUES(12),(25),(35))AS allCurrents(currentValues)它将选择最大值,在这种情况下为35. (27认同)
  • 这确实适用于2008并处理NULL.很好的解决方案. (9认同)
  • @Cheburek:从值(v),"value"是虚拟表的别名,"v"是日期值的虚拟列的名称. (9认同)
  • 这太棒了.我在哪里可以找到此Value()虚拟表的文档? (2认同)

ang*_*son 153

好吧,你可以使用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
Run Code Online (Sandbox Code Playgroud)

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

  • 显而易见的答案,但它不适用于NULL值,并尝试修复它会变得非常混乱. (21认同)
  • 使用`WHEN Date1> Date2 AND Date1> Date3 THEN Date1是不够的; 当Date2> Date3那么Date3; ELSE Date3`? (9认同)
  • Necro'ing这个较旧的帖子,但你可以将每个日期包装到COALESCE来处理NULL.其中一个WHEN语句将如下所示:WHEN Date1> = COALESCE(Date2,'')AND Date1> = COALESCE(Date3,'')那么Date3(对于另一个时做同样的事情) (5认同)
  • 顺便说一句,即使 Date3>Date1,当 Date2 为空时它也会返回 Date1。 (2认同)
  • 实际上这个答案应该被删除,因为它太糟糕了。不知道它是如何真正获得 178 票的,如果你的任何日期中有 NULL 值,它根本不起作用,这很常见。 (2认同)

baj*_*ife 132

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

SELECT GREATEST(col1, col2 ...) FROM table
Run Code Online (Sandbox Code Playgroud)

  • 是的,但仍然是一个非常有用的答案,因为人们在参考MySQL时会发现这个问题. (97认同)
  • 标签是sqlserver (40认同)
  • 现在在 Azure SQL 数据库中受支持,并且即将推出本地版本 https://techcommunity.microsoft.com/t5/azure-sql/introducing-the-greatest-and-least-t-sql-functions/ba-p/2281726 (5认同)
  • 也可以在[8.1]的PostgreSQL中找到(http://www.postgresql.org/docs/9.0/static/release-8-1.html). (4认同)
  • 太好了!它在PostgreSQL 9.4中运行良好 (3认同)
  • `LEAST(col1,col2 ...)`适用于最小值 (3认同)
  • 不能很好地处理NULL,但如果你在列值附近合并(col1,0)你将用气体烹饪,请参阅这个答案/sf/ask/688229601/最大-的-几个柱,但是,与空字段 (2认同)

Nii*_*ola 62

还有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
Run Code Online (Sandbox Code Playgroud)

解决方案1(UNPIVOT)

SELECT  number ,
        MAX(dDate) maxDate ,
        cost
FROM    dates UNPIVOT ( dDate FOR nDate IN ( Date1, Date2,
                                            Date3 ) ) as u
GROUP BY number ,
        cost 
GO
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

解决方案3(模拟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
Run Code Online (Sandbox Code Playgroud)

  • 好的!PIVOT/UNPIVOT 的非常规使用。有“迄今为止最快”的参考或证明吗? (3认同)

dat*_*yss 17

以下两个样本中的任何一个都可以使用:

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
Run Code Online (Sandbox Code Playgroud)

第二个是对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 
Run Code Online (Sandbox Code Playgroud)

  • 您应该使用 UNION ALL 而不是 UNION 以避免不必要的隐含 DISTINCT 操作。 (3认同)
  • 第一个答案很好,但可以大大简化。第二个答案不适用于 NULL 值。试图解决这个问题会变得非常混乱。 (2认同)

dok*_*ker 13

对于T-SQL(MSSQL 2008+)

SELECT
  (SELECT
     MAX(MyMaxName) 
   FROM ( VALUES 
            (MAX(Field1)), 
            (MAX(Field2)) 
        ) MyAlias(MyMaxName)
  ) 
FROM MyTable1
Run Code Online (Sandbox Code Playgroud)


小智 9

标量函数会导致各种性能问题,因此如果可能,最好将逻辑包装到内联表值函数中.这是我用来替换一些用户定义函数的函数,这些函数从最多十个日期的列表中选择最小/最大日期.在我的100万行数据集上测试时,标量函数花了15分钟才杀死查询,内联TVF花了1分钟,这与将结果集选择到临时表中的时间相同.要使用它,请从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)
)
Run Code Online (Sandbox Code Playgroud)


Mar*_*ith 8

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
Run Code Online (Sandbox Code Playgroud)


Nat*_*Nat 5

SELECT 
    CASE 
        WHEN Date1 >= Date2 AND Date1 >= Date3 THEN Date1 
        WHEN Date2 >= Date3 THEN Date2 
        ELSE Date3
    END AS MostRecentDate 
Run Code Online (Sandbox Code Playgroud)

在按顺序评估案例陈述时,这更容易写出并略过评估步骤.

  • 小心.如果Date2为NULL,则答案为Date3; 即使Date1更大. (3认同)

Dis*_*ned 5

不幸的是,Lasse 的回答虽然看起来很明显,但有一个关键的缺陷。它无法处理 NULL 值。任何单个 NULL 值都会导致 Date1 被返回。不幸的是,任何解决该问题的尝试都会变得非常混乱,并且不能很好地扩展到 4 个或更多值。

databyss 的第一个答案看起来(而且现在)很好。但是,不清楚该答案是否可以轻松地从多表连接中推断出 3 个值,而不是从单个表中推断出更简单的 3 个值。我想避免将这样的查询转换为子查询以获得最多 3 列,而且我很确定 databyss 的好主意可以稍微清理一下。

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

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
Run Code Online (Sandbox Code Playgroud)