尝试选择行并包含4列中的前2个不同的非空值

时间:2012-03-07 16:41:34

标签: sql sql-server database

我有一个看起来像这样的表:

CREATE TABLE [Test].[dbo].[MyTest]
(
[Id]    INT NOT NULL,
[ColA]  VARCHAR(255) NULL,
[ColB]  VARCHAR(255) NULL,
[ColC]  VARCHAR(255) NULL,
[ColD]  VARCHAR(255) NULL
);

让我说我有:

Id     ColA     ColB     ColC     ColD
---------------------------------------
1       A        B        NULL     C
2       A        A        NULL     D
3       NULL     A        B        NULL
4       B        B        B        B
5       NULL     NULL     NULL     NULL

我要做的是从该表中选择每一行,但只想按顺序从ColA-ColD中获取前两个不同的非空值。换句话说,如果是一行ColA& ColB都是非null并且彼此不同,那些是我想要的那一行。使用我上面给出的数据,此查询所需的结果将是:

1, A (from ColA), B (from ColB)
2, A (from ColA), D (from ColD)
3, A (from ColB), B (from ColC)
4, B (from ColA)

请注意,如果一行的ColA-D的所有数据都为NULL,则表示未选择该行。如果只有一个非空的不同列(你可以从结果行看到Id 4)也没关系 - 它不一定是2,但理想情况下它应该是2。

基本上我理想情况下能够从ColA-ColD获得TOP(2)DISTINCT WHERE这些都不是NULL,但我意识到TOP和DISTINCT在行上工作,而不是像我想要的那样在列上工作。非常感谢任何帮助。

谢谢!

3 个答案:

答案 0 :(得分:2)

对于CTE和CASE语句,这可能是最快的:

;WITH cte AS (
    SELECT id
          ,COALESCE(ColA, ColB, ColC, ColD) AS col1
          ,ColB
          ,ColC
          ,ColD
    FROM   tbl
    )
SELECT id
      ,col1
      ,CASE WHEN ColB <> col1 THEN ColB 
            WHEN ColC <> col1 THEN ColC
            WHEN ColD <> col1 THEN ColD
            ELSE                   NULL
       END AS col2
--    ,COALESCE(NULLIF(ColB, col1)
--             ,NULLIF(ColC, col1)
--             ,NULLIF(ColD, col1)) As col2   -- alt. syntax doing the same
FROM   cte
WHERE  col1 IS NOT NULL
ORDER  BY id

返回的第一列(col1)是第一个非空列,第二列(col2)是该顺序中的第二个不同的非空值。 CASE语句有效,因为NULL <> value永远不会评估为TRUE

如果只有一个不同的值,col2会返回NULL 如果所有源列均为NULL,则col1NULL,并且该行将按WHERE子句进行过滤。

NULLIF()的注释替代语法较短,但我不希望它更快。

答案 1 :(得分:0)

您的数据库设计看起来不对。

可能您不应该有ColA,..,ColD列。看起来您应该有第二个表格,其中包含idtype(A,..,D)和value

使用该结构,您可以轻松地获得任何输出。

答案 2 :(得分:0)

尝试:

select id,
       coalesce(ColA, ColB, ColC, ColD) Result1,
       coalesce(nullif(coalesce(ColB, ColC, ColD), coalesce(ColA, ColB, ColC, ColD)),
                nullif(coalesce(ColC, ColD), coalesce(ColB, ColC, ColD)),
                nullif(ColD, coalesce(ColC, ColD)) ) Result2
from [Test].[dbo].[MyTest]