получить некоторые столбцы таблицы имеют только нулевые значения - PullRequest
0 голосов
/ 05 июля 2018

Мне нужно знать, какие столбцы одной таблицы имеют только нулевые значения. Я понимаю, что я должен сделать цикл в user_tab_columns. Но как обнаружить только столбцы с нулевым значением? Спасибо и извините за мой английский

Ответы [ 3 ]

0 голосов
/ 05 июля 2018

Чтобы выполнить запрос, если вы не знаете, что столбец идентифицирует заранее, вам нужно использовать динамический 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 или эквивалент вашего клиента перед выполнением.

Курсор получает столбцы из таблицы, которые объявлены как обнуляемые (если это не так, нет особого смысла проверять их; хотя это не уловит явных проверочных ограничений). Для каждого столбца он создает запрос для подсчета строк, в которых этот столбец не равен нулю. Если этот счет равен нулю, то он не нашел ни одного, который не является нулевым, поэтому они все равны. Опять же, при условии, что вы знаете, что таблица не пуста до начала.

Я включил имя таблицы в список выбора курсора и ссылки, поэтому вам нужно всего лишь изменить имя в одном месте для поиска в другой таблице, или вы можете использовать переменную для этого имени. Или проверьте несколько таблиц одновременно, изменив этот фильтр.

Вы можете повысить производительность, выбрав фиктивное значение из любой ненулевой строки с проверкой остановки 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, но я предполагаю, что это разовая проверка, поэтому она, вероятно, приемлема.

0 голосов
/ 07 июля 2018

Первый вопрос: один столбец с нулевой строкой можно рассматривать как единственное (нулевое) значение, содержащее столбец. Но это может остаться вашим решением: приведенные ниже сценарии предоставляют решения в обоих направлениях. (На мой взгляд: нет. Пустые столбцы не являются столбцами с единственным (нулевым) значением)

Если вы хотите узнать (нулевые) значения для одной таблицы, вы можете сделать это с помощью count (столбца):

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
---------------

Счетчик () выбирает:

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. Уровень БД: все пользователи или выбранная схема

Количество (ноль) в одном столбце:

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.

0 голосов
/ 05 июля 2018

Вы можете зациклить ваши столбцы и считать пустые строки. Если он совпадает с количеством ваших таблиц, то в этом столбце есть только нулевые значения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...