获取表的某些列仅具有空值

时间:2018-07-05 16:59:27

标签: oracle plsql oracle11g

我需要知道一个表的哪些列仅具有空值。我知道我应该在user_tab_columns中进行循环。但是,如何仅检测具有空值的列? 谢谢,抱歉我的英语

3 个答案:

答案 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时,该列只有(空)值没有值。 (因此,您无法做出正确的决定。)

例如以下三个表(xyz)具有以下列:

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没有行或仅充满(空)值。

常规解决方案:

我已经分离了模式和数据库级别,但是基本思想很普遍:

  
      
  1. 架构级别:当前用户的表

  2.   
  3. 数据库级别:所有用户或选定的模式

  4.   

一栏中(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模式中仅具有(空)值。