我需要知道一个表的哪些列仅具有空值。我知道我应该在user_tab_columns中进行循环。但是,如何仅检测具有空值的列? 谢谢,抱歉我的英语
答案 0 :(得分:1)
要执行不知道该列预先标识的查询,您需要使用动态SQL。假设您已经知道表不为空,则可以执行以下操作:
declare
l_count pls_integer;
begin
for r in (
select table_name, column_name
from user_tab_columns
where table_name = 'T42'
and nullable = 'Y'
)
loop
execute immediate 'select count(*) '
|| ' from "' || r.table_name || '"'
|| ' where "' || r.column_name || '" is not null'
into l_count;
if l_count = 0 then
dbms_output.put_line('Table ' || r.table_name
|| ' column ' || r.column_name || ' only has nulls');
end if;
end loop;
end;
/
在执行之前,请记住set serveroutput on
或您的客户的等效帐户。
游标从表中获取被声明为可为空的列(如果不是,则不多检查点;尽管这不会捕获显式的检查约束)。对于每个列,它都会构建一个查询以对该列不为空的行进行计数。如果该计数为零,则找不到任何不为null的值,因此全部为空。同样,假设您知道表在开始之前就不是空的。
我已经将表名包含在光标选择列表和引用中,因此您只需要在一个位置更改名称即可搜索另一张表,或者可以为该名称使用变量。或通过更改该过滤器一次检查多个表。
通过使用rownum
停止检查从任何非空行中选择一个虚拟值,可能会获得更好的性能-这意味着它将在找到非空值后立即停止,而不必检查每一行以获得实际计数:
declare
l_flag pls_integer;
begin
for r in (
select table_name, column_name
from user_tab_columns
where table_name = 'T42'
and nullable = 'Y'
)
loop
begin -- inner block to allow exception trapping within loop
execute immediate 'select 42 '
|| ' from "' || r.table_name || '"'
|| ' where "' || r.column_name || '" is not null'
|| ' and rownum < 2'
into l_flag;
-- if this foudn anything there is a non-null value
exception
when no_data_found then
dbms_output.put_line('Table ' || r.table_name
|| ' column ' || r.column_name || ' only has nulls');
end;
end loop;
end;
/
或者您可以通过exists()
检查来做类似的事情。
如果您不知道表中有数据,则可以在循环之前从表中执行一个简单的count(*)
,以检查表是否为空,并报告该错误:
...
begin
if l_count = 0 then
dbms_output.put_line('Table is empty');
return;
end if;
...
或者您可以将其与游标查询结合使用,但是如果您想一次检查多个表,则需要做一些工作,因为一旦发现任何空表,它将立即停止(必须做些事。) 。* 8-)
declare
l_count_any pls_integer;
l_count_not_null pls_integer;
begin
for r in (
select table_name, column_name
from user_tab_columns
where table_name = 'T42'
and nullable = 'Y'
)
loop
execute immediate 'select count(*),'
|| ' count(case when "' || r.column_name || '" is not null then 1 end)'
|| ' from "' || r.table_name || '"'
into l_count_any, l_count_not_null;
if l_count_any = 0 then
dbms_output.put_line('Table ' || r.table_name || ' is empty');
exit; -- only report once
elsif l_count_not_null = 0 then
dbms_output.put_line('Table ' || r.table_name
|| ' column ' || r.column_name || ' only has nulls');
end if;
end loop;
end;
/
您当然可以填充集合或使其成为管道函数,或者如果您不想在dbms_output
上进行答复,则可以执行任何操作,但是我认为这是一次性检查,因此它可能是可接受的。 / p>
答案 1 :(得分:0)
您可以遍历列并计数空行。如果与您的表计数相同,则该列只有空值。
答案 2 :(得分:0)
第一个问题是:具有零行的一列可以被视为仅包含列的(空)值。但这仍然是您的决定:以下脚本提供了两种方法的解决方案。 (我认为:否。空列不是仅具有(空)值的列)
如果您想知道一张表的(空)值,可以使用count(column):
select count(column) from table
,当count(column) = 0
时,该列只有(空)值或没有值。 (因此,您无法做出正确的决定。)
例如以下三个表(x
,y
和z
)具有以下列:
select * from x;
N_X M_X
---------------
100 (null)
200 (null)
300 (null)
select * from y;
N_Y M_Y
---------------
101 (null)
202 (null)
303 apple
select * from z;
N_Z M_Z
---------------
count()选择:
select count(n_x), count(m_x) from x;
COUNT(N_X) COUNT(M_X)
-----------------------
3 0
select count(n_y), count(m_y) from y;
COUNT(N_Y) COUNT(M_Y)
-----------------------
3 1
select count(n_z), count(m_Z) from z;
COUNT(N_Z) COUNT(M_Z)
-----------------------
0 0
如您所见,出现了x和y之间的差异,但您不能确定表z没有行或仅充满(空)值。
常规解决方案:
我已经分离了模式和数据库级别,但是基本思想很普遍:
架构级别:当前用户的表
数据库级别:所有用户或选定的模式
一栏中(null)的数量:
all_tab_columns.num_nulls
(或: user_tab_columns, num_nulls
)。
我们需要表的num_rows:
all_all_tables.num_rows
(或: user_all_tables.num_rows
)
如果num_nulls等于num_rows,则只有(空)值。
首先,您需要运行DBMS_STATS来刷新统计信息。
在数据库级别:
exec DBMS_STATS.GATHER_DATABASE_STATS;
(它会占用很多资源)
在架构级别:
EXEC DBMS_STATS.gather_schema_stats('TRANEE',DBMS_STATS.AUTO_SAMPLE_SIZE);
(所有者=转录)
-- column with zero row = column has only (null) values -> exclude num_nulls > 0 condition
-- column with zero row <> column has only (null) values -> include num_nulls > 0 condition
脚本:
-- 1. current user
select
a.table_name,
a.column_name,
a.num_nulls,
b.num_rows
from user_tab_columns a, user_all_tables b
where a.table_name = b.table_name
and num_nulls = num_rows
and num_nulls > 0;
-- 2. chosen user / all user -> exclude the a.owner = 'TRANEE' condition
select
a.owner,
a.table_name,
a.column_name,
a.num_nulls,
b.num_rows
from all_tab_columns a, all_all_tables b
where a.owner = b.owner
and a.table_name = b.table_name
and a.owner = 'TRANEE'
and num_nulls = num_rows
and num_nulls > 0;
TABLE_NAME COLUMN_NAME NUM_NULLS NUM_ROWS
----------------------------------------------------
LEADERS COMM 4 4
EMP_ACTION ACTION 12 12
X M_X 3 3
这些表和列在tranee模式中仅具有(空)值。