我需要计算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.
错误在哪里?
提前致谢。
答案 0 :(得分:2)
为了计算表 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,我的意思是你可以
每个记录的每个NULLWITH 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
/
以下是一项改进,您现在只需要表名,而且基于它编写函数非常容易
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 变量中生成的代码针对并行运行进行了优化。
功能版本,还包括一个可选参数 ,可以在其他模式上运行。
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;