计算Oracle表中空值的数量?

时间:2017-06-08 18:29:18

标签: sql oracle plsql

我需要计算Oracle中表中所有列的空值数。

例如,我执行以下语句来创建表TEST并插入数据。

 CREATE TABLE TEST
 (  A VARCHAR2(20 BYTE), 
    B VARCHAR2(20 BYTE), 
    C VARCHAR2(20 BYTE)
  );
Insert into TEST (A) values ('a');
Insert into TEST (B) values ('b');
Insert into TEST (C) values ('c');

现在,我编写以下代码来计算表TEST中的空值数:

declare 
cnt number :=0;
temp number :=0;
begin
  for r in ( select column_name, data_type
             from    user_tab_columns 
             where table_name = upper('test')
             order by column_id )
  loop
      if r.data_type <> 'NOT NULL' then
         select count(*) into temp FROM TEST where r.column_name IS NULL;
         cnt := cnt + temp;
      END IF;
  end loop;
   dbms_output.put_line('Total: '||cnt);
end;
/

当预期值为6时,它返回0.

错误在哪里?

提前致谢。

5 个答案:

答案 0 :(得分:2)

为每列计算NULL

为了计算表 T 所有列的NULL值,您可以运行

SELECT COUNT(*) - COUNT(col1) col1_nulls
     , COUNT(*) - COUNT(col2) col2_nulls
     ,..
     , COUNT(*) - COUNT(colN) colN_nulls
     , COUNT(*) total_rows
FROM   T
/

其中 col1,col2,..,colN 应替换为 T 表的实际名称。

聚合函数 - 类似COUNT() - 忽略NULL值,因此COUNT(*) - COUNT(col)将为每列提供多少空值。

汇总表

的所有NULL

如果你想知道有多少字段是NULL,我的意思是你可以

每个记录的每个NULL
WITH d as (    
    SELECT COUNT(*) - COUNT(col1) col1_nulls
         , COUNT(*) - COUNT(col2) col2_nulls
         ,..
         , COUNT(*) - COUNT(colN) colN_nulls
         , COUNT(*) total_rows
    FROM   T
) SELECT col1_nulls + col1_nulls +..+ colN_null
  FROM d 
/

汇总表的所有NULL(使用Oracle字典表)

以下是一项改进,您现在只需要表名,而且基于它编写函数非常容易

DECLARE
  T    VARCHAR2(64) := '<YOUR TABLE NAME>';
  expr VARCHAR2(32767);
  q    INTEGER;
BEGIN
  SELECT 'SELECT /*+FULL(T) PARALLEL(T)*/' || COUNT(*) || ' * COUNT(*) OVER () - ' || LISTAGG('COUNT(' || COLUMN_NAME || ')', ' + ') WITHIN GROUP (ORDER BY COLUMN_ID) || ' FROM ' || T
  INTO   expr
  FROM   USER_TAB_COLUMNS
  WHERE  TABLE_NAME = T;

  -- This line is for debugging purposes only
  DBMS_OUTPUT.PUT_LINE(expr);

  EXECUTE IMMEDIATE expr INTO q;

  DBMS_OUTPUT.PUT_LINE(q);
END;
/

由于计算意味着全表扫描, expr 变量中生成的代码针对并行运行进行了优化。

用户定义的函数 null_fields

功能版本,还包括一个可选参数 ,可以在其他模式上运行。

CREATE OR REPLACE FUNCTION null_fields(table_name IN VARCHAR2, owner IN VARCHAR2 DEFAULT USER)
  RETURN INTEGER IS
  T    VARCHAR2(64) := UPPER(table_name);
  o    VARCHAR2(64) := UPPER(owner);
  expr VARCHAR2(32767);
  q    INTEGER;
BEGIN
  SELECT 'SELECT /*+FULL(T) PARALLEL(T)*/' || COUNT(*) || ' * COUNT(*) OVER () - ' || listagg('COUNT(' || column_name || ')', ' + ') WITHIN GROUP (ORDER BY column_id) || ' FROM ' || o || '.' || T || ' t'
  INTO   expr
  FROM   all_tab_columns
  WHERE  table_name = T;

  EXECUTE IMMEDIATE expr INTO q;

  RETURN q;
END;
/

-- Usage 1
SELECT null_fields('<your table name>') FROM dual
/

-- Usage 2
SELECT null_fields('<your table name>', '<table owner>') FROM dual
/

答案 1 :(得分:0)

谢谢@Lord Peter:

以下PL / SQL脚本工作

declare 
cnt number :=0;
temp number :=0;
begin
  for r in ( select column_name, nullable
             from    user_tab_columns 
             where table_name = upper('test')
             order by column_id )
  loop
      if r.nullable = 'Y' then
         EXECUTE IMMEDIATE 'SELECT count(*) FROM test where '|| r.column_name ||' IS NULL' into temp ;
         cnt := cnt + temp;
      END IF;
  end loop;
   dbms_output.put_line('Total: '||cnt);
end;
/

表格名称 test 可能会替换为您感兴趣的表格名称。

我希望这个解决方案很有用!

答案 2 :(得分:0)

您执行的动态SQL(这是EXECUTE IMMEDIATE中使用的字符串)应为

select sum(
    decode(a,null,1,0)
    +decode(b,null,1,0)
    +decode(c,null,1,0)
    ) nullcols
from test;

其中每个summand对应一个NOT NULL列。

此处只需一次表格扫描即可获得结果。

答案 3 :(得分:0)

使用数据字典几乎可以立即找到NULL值的数量:

select sum(num_nulls) sum_num_nulls
from all_tab_columns
where owner = user
    and table_name = 'TEST';

SUM_NUM_NULLS
-------------
6

如果最近收集了优化程序统计信息,并且使用样本大小的默认值收集了这些值,则这些值才会正确。

这些似乎是一个很大的警告,但无论如何,它值得熟悉您的数据库的统计数据收集过程。如果您的数据库自动收集统计信息,或者如果您的数据库使用默认样本大小,那么您可能需要注意这些问题。

要手动收集特定表的统计信息,这样的语句将起作用:

begin
    dbms_stats.gather_table_stats(user, 'TEST');
end;
/

答案 4 :(得分:-1)

select COUNT(1) TOTAL from table where COLUMN is NULL;