计算一行中NULL值的数量

Ela*_* L. 7 t-sql sql-server sql-server-2012

我想计算NULL一行中的值的数量.

例如:

Name    Col1    Col2      Col3     Col4 | ansCol
abc     null   a@c.com    null     null | 3
bbc     null    null      null     null | 4
Run Code Online (Sandbox Code Playgroud)

在这个例子中,答案很简单:

SELECT *,
(CASE WHEN Name IS NULL THEN 1 ELSE 0 END +
CASE WHEN Col1 IS NULL THEN 1 ELSE 0 END +       
CASE WHEN Col2 IS NULL THEN 1 ELSE 0 END +       
CASE WHEN Col3 IS NULL THEN 1 ELSE 0 END +       
CASE WHEN Col4 IS NULL THEN 1 ELSE 0 END) as ansCol
Run Code Online (Sandbox Code Playgroud)

当我们有一个非常宽的表,超过10列时,问题变得更加复杂.如果我尝试使用显示的方法,我会收到以下错误:

消息125,级别15,状态4,行13个案例表达式只能嵌套到级别10.

有没有办法克服这个问题?

Mar*_*ith 5

你的问题中的代码没有任何嵌套的情况,所以你应该能够将10个以上的链接加起来就好了.

但其他一些可能性......

如果所有列都具有相同的数据类型,则可以使用(Demo)

SELECT *,
       ansCol = (SELECT COUNT(*) - COUNT(C) FROM (VALUES(c1),(c2),(c3),(c4)) V(C))
FROM   t1 
Run Code Online (Sandbox Code Playgroud)

或者另一种不依赖于它们具有相同数据类型的替代方案.

;WITH XMLNAMESPACES('http://www.w3.org/2001/XMLSchema-instance' as ns)
SELECT *, 
        ansCol = (SELECT x.* FOR XML PATH('row'), 
                    ELEMENTS XSINIL, TYPE).value('count(/row/*[@ns:nil])', 'int') 
FROM   t1 x
Run Code Online (Sandbox Code Playgroud)


Den*_*Lee 1

除了上述之外,一种潜在的方法是使用PIVOTUNPIVOT功能。

让我们首先创建表并根据问题插入数据:

/* Create table */
CREATE TABLE so_40957006 (
    [name]  VARCHAR(24),
    [col1]  VARCHAR(24),
    [col2]  VARCHAR(24),
    [col3]  VARCHAR(24),
    [col4]  VARCHAR(24)
)

/* Insert data */
INSERT INTO so_40957006 VALUES('abc', null, 'a@c.com', null, null)
INSERT INTO so_40957006 VALUES('bbc', null, null, null, null)
Run Code Online (Sandbox Code Playgroud)

我们首先要做的是创建一个身份表,这样我们就可以唯一地标识每一行数据并插入数据。

/* Create identity table */
CREATE TABLE so_40957006_id (
    [lid]   INT IDENTITY(1, 1),
    [name]  VARCHAR(24),
    [col1]  VARCHAR(24),
    [col2]  VARCHAR(24),
    [col3]  VARCHAR(24),
    [col4]  VARCHAR(24)
)

/* Insert data into table */
INSERT INTO so_40957006_id 
SELECT 
  ISNULL([name], 1) AS [name]
 ,ISNULL([col1], 1) AS [col1]
 ,ISNULL([col2], 1) AS [col2]
 ,ISNULL([col3], 1) AS [col3]
 ,ISNULL([col4], 1) AS [col4]
FROM so_40957006
Run Code Online (Sandbox Code Playgroud)

请注意,在此过程中,我们已使用 将任何为 null 的列转换为值 1 IsNull。该表现在如下所示。

lid name    col1    col2    col3    col4
1   abc     1       a@c.com 1       1
2   bbc     1       1       1       1
Run Code Online (Sandbox Code Playgroud)

有了这个,我们现在可以使用PIVOTUNPIVOT垂直化数据。例如,运行下面的查询

SELECT [lid], [cols], [val]
FROM
    (SELECT [lid], [name], [col1], [col2], [col3], [col4]
        FROM so_40957006_id) p
UNPIVOT
    (val FOR cols IN 
    ([name], [col1], [col2], [col3], [col4])
) AS unpvt
Run Code Online (Sandbox Code Playgroud)

为您提供垂直输出:

lid cols    val
1   name    abc
1   col1    1
1   col2    a@c.com
1   col3    1
1   col4    1
2   name    bbc
2   col1    1
2   col2    1
2   col3    1
2   col4    1
Run Code Online (Sandbox Code Playgroud)

由于您要计数的值(即NULLs)的值为 1,因此您只需运行GROUP BY+SUM语句即可:

SELECT [lid], SUM(cast([val] as integer)) as CountNulls
  FROM (
    SELECT [lid], [cols], [val]
    FROM
        (SELECT [lid], [name], [col1], [col2], [col3], [col4]
           FROM so_40957006_id) p
    UNPIVOT
     (val FOR cols IN 
       ([name], [col1], [col2], [col3], [col4])
    ) AS unpvt
) a 
WHERE ISNUMERIC([val]) = 1
GROUP BY [lid]
Run Code Online (Sandbox Code Playgroud)

与输出

lid CountNulls
1   3
2   4
Run Code Online (Sandbox Code Playgroud)

[lid]您可以将此JOIN输出返回到原始表以生成结果集。