SQL按任意顺序查找第一个非空值

SQL按任意顺序查找第一个非空值,sql,sql-server,tsql,sql-server-2008-r2,Sql,Sql Server,Tsql,Sql Server 2008 R2,鉴于下表: ID | Value ---------- 1 | NULL 2 | B 3 | C 4 | NULL 我想根据不同的顺序从值列中获取第一个非空值,例如: SELECT FIRST_NON_NULL(Value ORDER BY ID) FROM MY_TABLE 这将返回B SELECT FIRST_NON_NULL(Value ORDER BY ID DESC) FROM MY_TABLE 这将返回C p.S.不必是一个值函数,只需要SELECT语句。多谢各位

鉴于下表:

ID | Value
----------
 1 | NULL
 2 |  B
 3 |  C
 4 | NULL
我想根据不同的顺序从值列中获取第一个非空值,例如:

SELECT FIRST_NON_NULL(Value ORDER BY ID) FROM MY_TABLE
这将返回B

SELECT FIRST_NON_NULL(Value ORDER BY ID DESC) FROM MY_TABLE
这将返回C

p.S.不必是一个值函数,只需要SELECT语句。多谢各位


已编辑:希望查看是否存在可扩展版本

ID | Value1 | Value2
--------------------
 1 |  NULL  |   AA
 2 |   B    |  NULL
 3 |   C    |   CC
 4 |  NULL  |  NULL

SELECT FIRST_NON_NULL(Value1, Value2 ORDER BY ID) FROM MY_TABLE
这将返回B,AA

SELECT FIRST_NON_NULL(Value1, Value2 ORDER BY ID DESC) FROM MY_TABLE
这将返回C,CC

只需执行以下操作:

SELECT TOP 1 Value
FROM mytable
WHERE Value IS NOT NULL
ORDER BY ID
要获取最后一个非空值开关,请执行以下操作:

ORDER BY ID DESC
要将相同逻辑扩展到更多列,可以使用以下查询:

SELECT (SELECT TOP 1 Value1 FROM mytable 
        WHERE Value1 IS NOT NULL ORDER BY ID) AS min_Value1,
       (SELECT TOP 1 Value2 FROM mytable 
        WHERE Value2 IS NOT NULL ORDER BY ID) AS min_Value2

DISTINCT语句用于仅返回不同(不同)的值


对于所提供的示例,原始答案肯定是最好的

对于那些需要在特定的分区中以及在大容量中执行此操作的人来说,这会成为一个问题,而且会非常严重,因为它会转化为后端的大量单个表点击

我有一个使用窗口函数的解决方案,可以解决大型数据/分区的问题

按如下方式展开原始示例数据-让我们在数据中有两个集合,基于GroupID(1和2):

我想为每个GroupID值提供这些第一个/最后一个非null值,如下所示:

GroupID | FirstValue1 | FirstValue2 | LastValue1 | LastValue2
-------------------------------------------------------------
1       | B           | AA          | C          | CC
2       | E           | EE          | F          | GG
如果我将top 1逻辑应用于scale,并且我有很多行,那么它将返回以执行大量的单个表查询。但是,如果我使用窗口函数,我可以让它评估内存中的数据,以更有效地获取数据,尤其是在需要分区和大量数据时

以下是解决方案:

SELECT
  GroupID,
  FirstValue1,
  FirstValue2,
  LastValue1,
  LastValue2
FROM
  (
  SELECT
    GroupID,
    ID, Value1, Value2,
    -- Sets a rank so we can reduce to 1 row per GroupID in outer query
    DENSE_RANK() OVER (
      PARTITION BY GroupID
      ORDER BY ID
    ) IDRank,
    FIRST_VALUE(Value1) OVER (
      PARTITION BY GroupID
      ORDER BY
        CASE WHEN Value1 IS NULL THEN 2 ELSE 1 END, -- Prioritize non-null Value1
        ID                                          -- And ascending ID
    ) FirstValue1,
    FIRST_VALUE(Value2) OVER (
      PARTITION BY GroupID
      ORDER BY
        CASE WHEN Value2 IS NULL THEN 2 ELSE 1 END, -- Prioritize non-null Value2
        ID                                          -- And ascending ID
    ) FirstValue2,
    FIRST_VALUE(Value1) OVER (
      PARTITION BY GroupID
      ORDER BY
        CASE WHEN Value1 IS NULL THEN 2 ELSE 1 END, -- Prioritize non-null Value1
        ID DESC                                     -- And descending ID
    ) LastValue1,
    FIRST_VALUE(Value2) OVER (
      PARTITION BY GroupID
      ORDER BY
        CASE WHEN Value2 IS NULL THEN 2 ELSE 1 END, -- Prioritize non-null Value2
        ID DESC                                     -- And descending ID
    ) LastValue2
  FROM MY_TABLE
  ) BestValues
WHERE IDRank = 1  --Ensures we get only one row per GroupID
ORDER BY GroupID
解释-第一个_值在每个不同的GroupID中求值(因为我们按GroupID设置分区)。在该窗口中,它计算GroupID的行中具有非空值的情况,然后按ID排序(升序或降序)。 由于它是一个窗口函数,这将值放在原始粒度的记录级别上,因此我们还添加了一个密集的_秩来进行排序,并使我们能够在外部查询中,将每个GroupID的行数减少到一行


p、 在美国,如果您想自己运行它,请在查询中包含以下内容,以将所需的样本数据生成到CTE中的“MY_表”中

WITH MY_TABLE AS (
  SELECT 0 as GroupID, 0 AS ID, CAST(NULL AS VARCHAR(10)) as Value1, CAST(NULL AS VARCHAR(10)) as Value2 WHERE 0=1 UNION ALL --Dummy row to set types

  SELECT 1 AS GroupID, 1 AS ID, NULL AS Value1, 'AA' AS Value2 UNION ALL
  SELECT 1 AS GroupID, 2 AS ID, 'B'  AS Value1, NULL AS Value2 UNION ALL
  SELECT 1 AS GroupID, 3 AS ID, 'C'  AS Value1, 'CC' AS Value2 UNION ALL
  SELECT 1 AS GroupID, 4 AS ID, NULL AS Value1, NULL AS Value2 UNION ALL
  SELECT 2 AS GroupID, 5 AS ID, 'E'  AS Value1, 'EE' AS Value2 UNION ALL
  SELECT 2 AS GroupID, 6 AS ID, 'F'  AS Value1, NULL AS Value2 UNION ALL
  SELECT 2 AS GroupID, 7 AS ID, NULL AS Value1, NULL AS Value2 UNION ALL
  SELECT 2 AS GroupID, 8 AS ID, NULL AS Value1, 'GG' AS Value2
)

在MySQL中,我相信大多数版本都可以使用,它只返回列表中的第一个非空值

您的查询最终将被删除

SELECT COALESCE(Value ORDER BY ID) FROM MY_TABLE

哇,太快了。谢谢。对不起,您如何使其可扩展?请参阅更新的问题。1值怎么可能不明显?这是正确答案。解决了查找问题并解决了性能问题。谢谢
WITH MY_TABLE AS (
  SELECT 0 as GroupID, 0 AS ID, CAST(NULL AS VARCHAR(10)) as Value1, CAST(NULL AS VARCHAR(10)) as Value2 WHERE 0=1 UNION ALL --Dummy row to set types

  SELECT 1 AS GroupID, 1 AS ID, NULL AS Value1, 'AA' AS Value2 UNION ALL
  SELECT 1 AS GroupID, 2 AS ID, 'B'  AS Value1, NULL AS Value2 UNION ALL
  SELECT 1 AS GroupID, 3 AS ID, 'C'  AS Value1, 'CC' AS Value2 UNION ALL
  SELECT 1 AS GroupID, 4 AS ID, NULL AS Value1, NULL AS Value2 UNION ALL
  SELECT 2 AS GroupID, 5 AS ID, 'E'  AS Value1, 'EE' AS Value2 UNION ALL
  SELECT 2 AS GroupID, 6 AS ID, 'F'  AS Value1, NULL AS Value2 UNION ALL
  SELECT 2 AS GroupID, 7 AS ID, NULL AS Value1, NULL AS Value2 UNION ALL
  SELECT 2 AS GroupID, 8 AS ID, NULL AS Value1, 'GG' AS Value2
)
SELECT COALESCE(Value ORDER BY ID) FROM MY_TABLE