【问题标题】:Count number of NULL values in a row计算一行中 NULL 值的数量
【发布时间】:2016-12-04 08:58:17
【问题描述】:

我想连续计算NULL 值的数量。

例如:

Name    Col1    Col2      Col3     Col4 | ansCol
abc     null   a@c.com    null     null | 3
bbc     null    null      null     null | 4

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

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

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

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

有什么办法可以克服吗?

【问题讨论】:

  • 我用 Case 13 列,没有问题吗?我是不是做错了什么?
  • @ahmedab​​delqader 请在问题下方而不是每个人的答案下方留下这样的评论。
  • @TimBiegeleisen 完成。
  • 嵌套在哪里???

标签: sql-server tsql sql-server-2012


【解决方案1】:

您问题中的代码没有任何 嵌套 案例,因此您应该能够将 10 多个加法链接在一起。

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

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

SELECT *,
       ansCol = (SELECT COUNT(*) - COUNT(C) FROM (VALUES(c1),(c2),(c3),(c4)) V(C))
FROM   t1 

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

;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

【讨论】:

    【解决方案2】:

    除了上述之外,一种可能的方法是使用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)
    

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

    /* 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
    

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

    lid name    col1    col2    col3    col4
    1   abc     1       a@c.com 1       1
    2   bbc     1       1       1       1
    

    有了这个,我们现在可以使用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
    

    为您提供以下垂直输出:

    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
    

    由于您要计算的值(即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]
    

    输出

    lid CountNulls
    1   3
    2   4
    

    使用[lid],您可以将JOIN 这个输出返回到原始表以生成您的结果集。

    【讨论】:

      【解决方案3】:

      这感觉像是一种 hack,也许您应该更改您的设计或减少表中的列数,但如果您必须这样做,一个选项是使用子查询来绕过 10 列嵌套限制:

      SELECT t.*,
             t.firstBatch + t.secondBatch AS ansCol
      FROM
      (
          SELECT *,
              (CASE WHEN Col1 IS NULL THEN 1 ELSE 0 END +  
               CASE WHEN Col2 IS NULL THEN 1 ELSE 0 END +       
               ...
               CASE WHEN Col10 IS NULL THEN 1 ELSE 0 END) AS firstBatch,
              (CASE WHEN Col11 IS NULL THEN 1 ELSE 0 END +  
               CASE WHEN Col12 IS NULL THEN 1 ELSE 0 END +       
               ...
               CASE WHEN Col20 IS NULL THEN 1 ELSE 0 END) AS secondBatch
          FROM yourTable
      ) t
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-05
        • 1970-01-01
        • 2018-06-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-09-19
        相关资源
        最近更新 更多