繁体   English   中英

将空值的数量计入Oracle表中?

[英]Count the number of null values into an Oracle table?

我需要计算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。

错误在哪里?

提前致谢。

计算每列的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
/

谢谢@彼得大爷:

下面的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;
/

表名测试可以替换为您感兴趣的表名。

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

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

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

其中每个加数对应于一个NOT NULL列。

在这里,只需要进行一次表扫描即可获得结果。

使用数据字典几乎可以立即找到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;
/
select COUNT(1) TOTAL from table where COLUMN is NULL;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM