SQL使用任意顺序查找第一个非空值
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL使用任意顺序查找第一个非空值相关的知识,希望对你有一定的参考价值。
鉴于下表:
ID | Value
----------
1 | NULL
2 | B
3 | C
4 | NULL
我想根据不同的顺序从Value列中获取第一个非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.
附:不必是值函数,只需要所需的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
原始答案绝对是所提供示例的最佳答案。
对于那些需要在特定分区和大容量内执行此操作的人来说,这会变得有问题和密集,因为它可以转化为后端的大量单个表命中。
我有一个使用窗口函数的解决方案,解决了大数据/分区的问题。
扩展原始示例数据如下 - 让我们在数据中有两个集合,基于GroupID(1和2):
GroupID | ID | Value1 | Value2
--------------------------
1 | 1 | NULL | AA
1 | 2 | B | NULL
1 | 3 | C | CC
1 | 4 | NULL | NULL
2 | 5 | E | EE
2 | 6 | F | NULL
2 | 7 | NULL | GG
2 | 8 | NULL | NULL
我想为每个GroupID值提供这些第一个/最后一个非空值,如下所示:
GroupID | FirstValue1 | FirstValue2 | LastValue1 | LastValue2
-------------------------------------------------------------
1 | B | AA | C | CC
2 | E | EE | F | GG
如果我应用前1个逻辑来扩展,并且我有很多行,那么它将返回执行大量的单个表查询。但是,如果我使用窗口函数,我可以让它评估它在内存中的数据,以便更有效地获取数据,特别是在需要分区和大量数据时。
这是解决方案:
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
解释 - FIRST_VALUE在每个不同的GroupID内进行评估(因为我们设置了PARTITION BY GroupID)。在该窗口中,它评估该GroupID的行,具有非空值的情况,然后按ID排序(升序或降序)。由于它是一个窗口函数,因此将值放在记录级别上的原始粒度,因此我们还添加了一个DENSE_RANK来排名,并使我们能够在外部查询中将每个GroupID下降到一行。
p.s.,如果您想自己运行它,请在查询上方包含以下内容,以便在CTE中将所需的样本数据生成为“MY_TABLE”。
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
)
DISTINCT语句用于仅返回不同的(不同的)值
SELECT distinct TOP 1 Value
FROM mytable
WHERE Value IS NOT NULL
ORDER BY ID desc
以上是关于SQL使用任意顺序查找第一个非空值的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 2008 R2:从列中获取第一个非空值