【问题标题】:SQL: Select the minimum value from multiple columns with null valuesSQL:从具有空值的多个列中选择最小值
【发布时间】:2015-06-15 10:34:51
【问题描述】:

我有一张这样的桌子

ID   Col1   Col2   Col3
--   ----   ----   ----
1      7    NULL    12  
2      2     46    NULL
3     NULL  NULL   NULL
4     245     1    792

我想要一个产生以下结果的查询

 ID   Col1   Col2   Col3  MIN
 --   ----   ----   ----  ---
  1     7    NULL    12    7
  2     2     46    NULL   2
  3    NULL  NULL   NULL  NULL
  4    245    1     792    1

我的意思是,我想要一列包含 Col1、Col2 和 Col 3 中的最小值,每行忽略 NULL 值。在上一个问题 (What's the best way to select the minimum value from multiple columns?) 中,有一个非 NULL 值的答案。对于一个巨大的表,我需要一个尽可能高效的查询。

Select Id,
       Case When Col1 < Col2 And Col1 < Col3 Then Col1
            When Col2 < Col1 And Col2 < Col3 Then Col2 
            Else Col3
            End As MIN
From   YourTableNameHere

【问题讨论】:

  • 您使用的是什么数据库?您应该适当地标记您的问题。

标签: sql select


【解决方案1】:

假设您可以定义一些您的实际值永远不会超过的“最大值”(我将在此处使用 9999):

Select Id,
       Case When Col1 < COALESCE(Col2, 9999)
             And Col1 < COALESCE(Col3, 9999) Then Col1
            When Col2 < COALESCE(Col1, 9999) 
             And Col2 < COALESCE(Col3, 9999) Then Col2 
            Else Col3
       End As MIN
    From YourTableNameHere;

【讨论】:

    【解决方案2】:

    您没有指定您使用的 Teradata 版本。如果您使用的是 14+ 版本,则可以使用 least

    不幸的是,如果 least 的任何参数为 null,则它会返回 null。来自文档:

    LEAST 支持 1-10 个数值。 如果 numeric_value 是第一个参数的数据类型,则返回 数据类型是数字。输入列表中的其余参数必须 是相同或兼容的类型。如果任一输入参数为 NULL, 返回 NULL。

    但是你可以通过使用 coalesce 来解决这个问题,就像 Joe 在他的回答中所做的那样。

    select id, 
      least(coalesce(col1,9999),coalesce(col2,9999),coalesce(col3,9999))
    from mytable
    

    【讨论】:

      【解决方案3】:

      这可能有效:

      Select id, Col1, Col2, Col3, least(Col1, Col2, Col3) as MIN From YourTableNameHere
      

      【讨论】:

      • LEAST 并非在所有数据库中都实现。我知道它在 Oracle 和 MySQL 中,但不在 SQL Server 中。
      【解决方案4】:

      这样你就不需要检查nulls,只需使用minsubquery

      select tbl.id,tbl.col1,tbl.col2,tbl.col3,
            (select min(t.col) 
            from ( 
                  select col1 as col from tbl_name t where t.id=tbl.id
                  union all
                  select col2 as col from tbl_name t where t.id=tbl.id
                  union all
                  select col3 as col from tbl_name t where t.id=tbl.id 
                 )t) 
      from tbl_name tbl
      

      输出:

      1   7       NULL    12      7
      2   2       46      NULL    2
      3   NULL    NULL    NULL    NULL
      4   245     1       792     1
      

      【讨论】:

      • 我怀疑这些相关的子查询对于 OP 指定的“巨大表”来说表现不佳。
      • 是的,老实说,我正在使用 coalesce 和 case 语句编写解决方案,但你在我面前发布了一个,所以我想换一种方式说
      【解决方案5】:

      只需使用coalesce()修改您的查询:

      Select Id,
             (Case When Col1 <= coalesce(Col2, col3, col1) And
                        Col1 <= coalesce(Col3, col2, col1)
                  Then Col1
                  When Col2 <= coalesce(Col1, col3, col2) And
                       Col2 <= coalesce(Col3, col1, col2)
                  Then Col2 
                  Else Col3
              End) As MIN
      From YourTableNameHere;
      

      这不需要发明一个“神奇”的数字或过度复杂的逻辑。

      【讨论】:

        【解决方案6】:

        我发现此解决方案比使用多个 case 语句子句更有效,后者在评估一行中多个列的数据时会变得非常冗长。

        另外,我不能相信这个解决方案,因为我大约一年前在某个网站上发现了它。今天我需要刷新这个逻辑,但我在任何地方都找不到。我找到了我的旧代码,并决定现在在这个论坛上分享它。

        创建您的测试表:

        create table #testTable(ID int, Col1 int, Col2 int, Col3 int)
        Insert into #testTable values(1,7,null,12)
        Insert into #testTable values(2,2,46,null)
        Insert into #testTable values(3,null,null,null)
        Insert into #testTable values(4,245,1,792)
        

        在行数据中查找最小值:

        Select ID, Col1, Col2, Col3 ,(SELECT Min(v) FROM (  VALUES  (Col1), (Col2), (Col3)  ) AS value(v)) [MIN] from #testTable order by ID
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-08-05
          • 1970-01-01
          • 2020-07-23
          • 2014-12-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多