【问题标题】:Count the Null columns in a row in SQL在 SQL 中计算一行中的 Null 列
【发布时间】:2011-12-21 21:18:21
【问题描述】:

我想知道在 SQL 中计算行的空列的可能性,我有一个表 Customer 具有可为空的值,只是我想要一个查询返回某个行的空列数的 int(某些客户)。

【问题讨论】:

  • 这不是你应该在 sql 中做的事情
  • 出于我自己的好奇心,你为什么想知道这个?
  • 什么关系型数据库?什么是列?它们都是相同的数据类型吗?
  • 你的意思是针对这种情况的任何解决方案都是丑陋的解决方案?
  • @SpectralGhost 情况是我想为客户构建一个进度条来填写他的信息,所以我需要获取列的总数和为空的列数所以我可以得到填充数据的百分比。

标签: sql


【解决方案1】:

此方法为空列分配 1 或 0,并将它们加在一起。希望这里没有太多可空列要加起来...

SELECT 
  ((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 col10 IS NULL THEN 1 ELSE 0 END)) AS sum_of_nulls
FROM table
WHERE Customer=some_cust_id

请注意,如果您的 RDBMS 支持,您也可以使用 IF() 在语法上更简洁地执行此操作。

SELECT 
  (IF(col1 IS NULL, 1, 0)
  + IF(col2 IS NULL, 1, 0)
  + IF(col3 IS NULL, 1, 0)
  ...
  ...
  + IF(col10 IS NULL, 1, 0)) AS sum_of_nulls
FROM table
WHERE Customer=some_cust_id

我在一张桌子上测试了这个模式,它似乎工作正常。

【讨论】:

  • IF() 可能在语法上看起来更干净,但CASE 得到更普遍的支持。尽管如此,为了继续这条路线,从最通用的解决方案到最干净的解决方案,我建议如下:SELECT ((col1 IS NULL) + (col2 IS NULL) + ...) AS sum_of_nulls FROM ....
  • @ImanMarashi 我不确定你在问什么。此查询的结果是一个整数列,表示每行 NULL 列的计数。
【解决方案2】:

我的答案基于Michael Berkowski's answer,但为了避免输入数百个列名,我所做的是:

第 1 步:获取表格中所有列的列表

SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'myTable';

第 2 步: 将列表粘贴到 Notepad++ 中(任何支持正则表达式替换的编辑器都可以使用)。然后使用这个替换模式

  • 搜索:

    ^(.*)$
    
  • 替换:

    \(CASE WHEN \1 IS NULL THEN 1 ELSE 0 END\) +
    

第 3 步:SELECT identityColumnName, 添加到前面,并将最后的 + 更改为 AS NullCount FROM myTable,并可选择添加 ORDER BY...

SELECT 
    identityColumnName, 
    (CASE WHEN column001 IS NULL THEN 1 ELSE 0 END) +
    -- ...
    (CASE WHEN column200 IS NULL THEN 1 ELSE 0 END) AS NullCount
FROM
    myTable
ORDER BY 
    NullCount DESC

【讨论】:

  • 您也可以使用 sys.columns 或类似的东西来连接所有这些而不需要像记事本这样的东西。
【解决方案3】:

仅适用于 ORACLE-DBMS。

你可以使用NVL2函数:

NVL2( string1, value_if_not_null, value_if_null )

这是一个与 Michael Berkowski 建议的方法类似的选择:

SELECT (NVL2(col1, 0, 1) 
        + NVL2(col2, 0, 1)
        + NVL2(col3, 0, 1)
        ...
        ...
        + NVL2(col10, 0, 1)
        ) AS sum_of_nulls
FROM table
WHERE Customer=some_cust_id

更通用的方法是编写 PL/SQL 块并使用动态 SQL。您必须使用上面的 NVL2 方法为特定表的 all_tab_columns 中的每一列构建一个 SELECT 字符串。

【讨论】:

    【解决方案4】:

    不幸的是,在标准 SQL 语句中,您必须输入要测试的每一列,以编程方式测试所有您可以使用 T-SQL 的列。不过请注意,请确保您使用的是真正的 NULLS,您可以有空白的存储值,数据库不会将其识别为真正的 NULL(我知道这听起来很奇怪)。

    您可以通过在如下语句中捕获空白值和 NULLS 来避免这种情况:

    CASE WHEN col1 & '' = '' THEN 1 ELSE 0 END
    

    或者在 Oracle 等一些数据库中(不确定是否还有其他数据库),您会使用:

    CASE WHEN col1 || '' = '' THEN 1 ELSE 0 END
    

    【讨论】:

      【解决方案5】:

      您没有声明 RDBMS。对于 SQL Server 2008...

      SELECT CustomerId,
             (SELECT COUNT(*) - COUNT(C)
              FROM   (VALUES(CAST(Col1 AS SQL_VARIANT)),
                            (Col2),
                            /*....*/
                            (Col9),
                            (Col10)) T(C)) AS NumberOfNulls
      FROM   Customer  
      

      【讨论】:

        【解决方案6】:

        取决于你想做什么,如果你忽略 maven,如果你使用 SQL Server 2012,你可以用另一种方式。 .

        必须知道候选列(“槽”)的总数。 1. 逐列选择所有已知的“插槽”(它们是已知的)。 2. 取消旋转该结果以获得 每原始列一行的表。这有效,因为空列不 unpivot,并且您知道所有列名。 3.count(*)结果得到非空的个数; 从中减去得到你的答案。

        像这样,一辆车有 4 个“座位”

        select 'empty seats' = 4 - count(*)
        from 
        (
            select carId, seat1,seat2,seat3,seat4 from cars where carId = @carId
        ) carSpec
        unpivot (FieldValue FOR seat in ([seat1],[seat2],[seat3],[seat4])) AS results
        

        如果您可能需要稍后做更多的事情而不仅仅是计算非空列的数量,这很有用,因为它也为您提供了一种将列作为一个集合进行操作的方法。

        【讨论】:

          【解决方案7】:

          这将为您提供不为空的列数。你可以适当地应用它

          SELECT   ISNULL(COUNT(col1),'') + ISNULL(COUNT(col2),'') +ISNULL(COUNT(col3),'') 
             FROM TABLENAME
             WHERE  ID=1
          

          【讨论】:

          • 严格来说,ISNULL() 不是必需的,因为COUNT(*) 返回一个值。请注意,ISNULL() 并非在每个系统上都存在,并且 OP 从未指定他使用的 RDBMS,这意味着答案可能对他也不起作用。最后...如果COUNT() 以某种方式确实 返回了一个null,那么您返回一个blank 的事实将导致此操作失败;要么你得到一个字符串而不是总数,要么数据库抱怨类型不匹配。为此,事实上这个问题已经有将近 2 年的历史了,而且答案已经被接受,-1(虽然基本想法有效)
          【解决方案8】:

          下面的脚本为您提供一行内的NULL 值计数,即有多少列没有值。

          {SELECT
              *,
              (SELECT COUNT(*)
              FROM (VALUES (Tab.Col1)
                          ,(Tab.Col2)
                          ,(Tab.Col3)
                          ,(Tab.Col4)) InnerTab(Col) 
                  WHERE Col IS NULL) NullColumnCount
          FROM (VALUES(1,2,3,4)
                      ,(NULL,2,NULL,4)
                      ,(1,NULL,NULL,NULL)) Tab(Col1,Col2,Col3,Col4) } 
          

          只是为了证明我在示例中使用了内联表。

          尝试将所有列值转换或转换为通用类型,这将帮助您比较不同类型的列。

          【讨论】:

          • 我不熟悉“InnerTab”。我用谷歌搜索并找不到定义。有人可以为我提供关于这意味着什么的线索吗?
          【解决方案9】:

          我还没有测试过,但我会尝试使用 PL\SQL 函数来测试它

          CREATE OR REPLACE TYPE ANYARRAY AS TABLE OF ANYDATA
          ;
          
          CREATE OR REPLACE Function COUNT_NULL
          ( ARR IN ANYARRAY )
          RETURN number
          IS
             cnumber number ;
          BEGIN
          
             for i in 1 .. ARR.count loop
               if ARR(i).column_value is null then
                 cnumber := cnumber + 1;
               end if;
             end loop;
          
          RETURN cnumber;
          
          EXCEPTION
          WHEN OTHERS THEN
             raise_application_error
             (-20001,'An error was encountered - '
             ||SQLCODE||' -ERROR- '||SQLERRM);
          END
          ;
          

          然后在这样的选择查询中使用它

          CREATE TABLE TEST (A NUMBER, B NUMBER, C NUMBER);
          
          INSERT INTO TEST (NULL,NULL,NULL);
          INSERT INTO TEST (1   ,NULL,NULL);
          INSERT INTO TEST (1   ,2   ,NULL);
          INSERT INTO TEST (1   ,2   ,3   );
          
          SELECT ROWNUM,COUNT_NULL(A,B,C) AS NULL_COUNT FROM TEST;
          

          预期输出

          ROWNUM | NULL_COUNT
          -------+-----------
               1 | 3
               2 | 2
               3 | 1
               4 | 0
          

          【讨论】:

            【解决方案10】:

            我就是这样尝试的

            CREATE TABLE #temptablelocal (id int NOT NULL, column1 varchar(10) NULL, column2 varchar(10) NULL, column3 varchar(10) NULL, column4 varchar(10) NULL, column5 varchar(10) NULL, column6 varchar(10) NULL);
            
            
            INSERT INTO #temptablelocal
            VALUES (1,
                    NULL,
                    'a',
                    NULL,
                    'b',
                    NULL,
                    'c')
            SELECT *
            FROM #temptablelocal
            WHERE id =1
              SELECT count(1) countnull
              FROM
                (SELECT a.ID,
                        b.column_title,
                        column_val = CASE b.column_title    
                        WHEN 'column1' THEN a.column1 
                        WHEN 'column2' THEN a.column2 
                        WHEN 'column3' THEN a.column3 
                        WHEN 'column4' THEN a.column4 
                        WHEN 'column5' THEN a.column5 
                        WHEN 'column6' THEN a.column6 
                        END
                 FROM
                   ( SELECT id,
                            column1,
                            column2,
                            column3,
                            column4,
                            column5,
                            column6
                    FROM #temptablelocal
                    WHERE id =1 ) a
                 CROSS JOIN
                   ( SELECT 'column1'
                    UNION ALL SELECT 'column2'
                    UNION ALL SELECT 'column3'
                    UNION ALL SELECT 'column4'
                    UNION ALL SELECT 'column5'
                    UNION ALL SELECT 'column6' ) b (column_title) ) AS pop WHERE column_val IS NULL
              DROP TABLE #temptablelocal
            

            【讨论】:

              【解决方案11】:

              类似,但动态:

              drop table if exists myschema.table_with_nulls;
              
              create table myschema.table_with_nulls as
              
              select 
                 n1::integer,
                 n2::integer,
                 n3::integer,
                 n4::integer,
                 c1::character varying,
                 c2::character varying,
                 c3::character varying,
                 c4::character varying
              from 
                 (
                    values 
                       (1,2,3,4,'a','b','c','d'),
                       (1,2,3,null,'a','b','c',null),
                       (1,2,null,null,'a','b',null,null),
                       (1,null,null,null,'a',null,null,null)
                 ) as test_records(n1, n2, n3, n4, c1, c2, c3, c4);
              
              
              drop function if exists myschema.count_nulls(varchar,varchar);
              
              create function myschema.count_nulls(schemaname varchar, tablename varchar) returns void as 
              $BODY$
                 declare
                    calc varchar;
                    sqlstring varchar;
              begin
                 select
                    array_to_string(array_agg('(' || trim(column_name) || ' is null)::integer'),' + ') 
                 into
                    calc
                 from
                    information_schema.columns
                 where 
                    table_schema in ('myschema') 
                       and table_name in ('table_with_nulls'); 
              
                 sqlstring = 'create temp view count_nulls as select *, ' || calc || '::integer as count_nulls from myschema.table_with_nulls';
              
                 execute sqlstring;
              
                 return;
              end;
              $BODY$ LANGUAGE plpgsql STRICT;
              
              select * from myschema.count_nulls('myschema'::varchar,'table_with_nulls'::varchar);
              
              
              select
                 *
              from 
                 count_nulls;
              

              虽然我看到我没有完成函数的参数化。

              【讨论】:

                【解决方案12】:

                我的答案建立在Drew Chapin's answer 的基础上,但进行了更改以使用单个脚本获得结果:

                use <add_database_here>;
                Declare @val Varchar(MAX); 
                
                Select @val = COALESCE(@val + str, str) From 
                    (SELECT
                    '(CASE WHEN '+COLUMN_NAME+' IS NULL THEN 1 ELSE 0 END) +' str
                    FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '<add table name here>'
                    ) t1 -- getting column names and adding the case when to replace NULLs for zeros or ones
                    
                Select @val = SUBSTRING(@val,1,LEN(@val) - 1) -- removing trailling add sign
                    
                Select @val = 'SELECT <add_identity_column_here>, ' + @val + ' AS NullCount FROM <add table name here>' -- adding the 'select' for the column identity, the 'alias' for the null count column, and the 'from'
                
                EXEC (@val) --executing the resulting sql
                

                【讨论】:

                  【解决方案13】:

                  没有像计数行那样直接的方法。基本上,您必须在一个表达式中枚举所有可能为空的列。

                  因此,对于可能包含空列 ab, c 的表,您可以这样做:

                  SELECT key_column, COALESCE(a,0) + COALESCE(b,0) + COALESCE(c,0) null_col_count
                    FROM my_table
                  

                  【讨论】:

                  • 这行不通。如果 a,b,c 不是数字,则会引发错误。如果它们是数字,它将返回错误的结果。
                  猜你喜欢
                  • 1970-01-01
                  • 2021-09-15
                  • 2022-08-23
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-06-21
                  • 1970-01-01
                  • 2012-12-05
                  • 1970-01-01
                  相关资源
                  最近更新 更多