Главная > oracle, SQL > Поиск значения по всем таблицам


Поиск значения по всем таблицам

Поиск значения по всем таблицам

Вариант1:

DECLARE
  match_count   INTEGER;
  query_str     VARCHAR2(400);
  l_owner       VARCHAR2(10)  := 'SCOTT';
  l_search_text VARCHAR2(100) := '10';
BEGIN
  FOR t IN (select table_name, column_name FROM all_tab_columns a
            where owner = l_owner
                  and a.data_type in ('NUMBER', 'VARCHAR2')
            )
  LOOP
    begin
      match_count := 0;
      query_str   := 'SELECT COUNT(*) FROM ' ||l_owner||'.'|| t.table_name ||
                     ' WHERE to_char(' || t.column_name || ') = :1';
      EXECUTE IMMEDIATE query_str
        INTO match_count
        USING l_search_text;
      IF match_count > 0 THEN
        dbms_output.put_line(l_owner||'.'||t.table_name || ' ' || t.column_name || ' ' || match_count);
        dbms_output.put_line('  SELECT t.'|| t.column_name || ', t.* from '||l_owner||'.'|| t.table_name||' t where to_char(' || t.column_name || ') = '''||l_search_text||'''');
        dbms_output.put_line('');
      END IF;
    exception
     when others then
       dbms_output.put_line(t.table_name||'.'||t.column_name||' : '||SQLERRM||' : '||SQLCODE);
       dbms_output.put_line(query_str);
       dbms_output.put_line('');
       /*raise*/
    end;
  END LOOP;
END;

Вариант2:

--SET SERVEROUTPUT ON SIZE 1000000
DECLARE
  TYPE tab_columns_rec_type IS RECORD (
    table_name   all_tab_columns.table_name%type
   ,column_name  all_tab_columns.column_name%type
   ,data_type    all_tab_columns.data_type%type
  );
  type tab_columns_tab_type is table of tab_columns_rec_type index by binary_integer;
  l_tab_columns_rec tab_columns_tab_type;
 
  match_count   INTEGER;
  query_str     VARCHAR2(400);
  l_owner       VARCHAR2(10)  := 'SCOTT';
  l_search_text VARCHAR2(100) := '10'; -- % добавляем здесь, если ищем не по точному вхождению
  l_number      NUMBER;
  is_number     NUMBER(1);
  l_str_length  NUMBER;
  /*
  l_mode:
  1 - NUMBER и VARCHAR2
  2 - only NUMBER
  3 - only VARCHAR2
  */
  l_mode NUMBER := 1;
  -- При каком количестве найденные совпадений
  -- прекращать поиск
  l_found_count  NUMBER := 1; 
  l_exists_count NUMBER;
BEGIN
 
  l_str_length := length(l_search_text);
 
  begin
    l_number := to_number(l_search_text);
    is_number := 1;
  exception
    when VALUE_ERROR then
      is_number := 0;
  end;
 
  if (l_mode = 1 and is_number = 1) then
    select table_name, column_name, data_type
      bulk collect into l_tab_columns_rec
    FROM all_tab_columns a
    where owner = l_owner
          and a.data_length >= l_str_length
          and ( a.data_type = 'VARCHAR2' or a.data_type = 'NUMBER' );
  elsif (l_mode = 2 and is_number = 1) then
    select table_name, column_name, data_type
      bulk collect into l_tab_columns_rec
    FROM all_tab_columns a
    where owner = l_owner
          and a.data_length >= l_str_length
          and a.data_type = 'NUMBER';
  else
    select table_name, column_name, data_type
      bulk collect into l_tab_columns_rec
    FROM all_tab_columns a
    where owner = l_owner
          and a.data_length >= l_str_length
          and a.data_type = 'VARCHAR2';
  end if;
  l_exists_count := 0;
  if NOT (l_tab_columns_rec is null or l_tab_columns_rec.count = 0) then
    for j in l_tab_columns_rec.first..l_tab_columns_rec.last
    LOOP
        begin
          match_count := 0;
          if (l_tab_columns_rec(j).data_type = 'VARCHAR2') then
            query_str   := 'SELECT count(*) FROM ' ||l_owner||'.'|| l_tab_columns_rec(j).table_name ||
                           ' WHERE rownum = 1 and to_char(' || l_tab_columns_rec(j).column_name || ') = :1';
            EXECUTE IMMEDIATE query_str
              INTO match_count
              USING l_search_text;
          elsif (l_tab_columns_rec(j).data_type = 'NUMBER') then
            query_str   := 'SELECT count(*) FROM ' ||l_owner||'.'|| l_tab_columns_rec(j).table_name ||
                           ' WHERE rownum = 1 and ' || l_tab_columns_rec(j).column_name || ' = :1';
            EXECUTE IMMEDIATE query_str
              INTO match_count
              USING l_number;
          end if;
 
          IF match_count > 0 THEN
            l_exists_count := l_exists_count + 1;
            dbms_output.put_line(l_tab_columns_rec(j).data_type||' '||l_owner||'.'||l_tab_columns_rec(j).table_name || ' ' || l_tab_columns_rec(j).column_name );
            dbms_output.put_line('  SELECT t.'|| l_tab_columns_rec(j).column_name || ', t.* from '||l_owner||'.'|| l_tab_columns_rec(j).table_name||' t where to_char(' || l_tab_columns_rec(j).column_name || ') like '''||l_search_text||'''');
            dbms_output.put_line('');
            if (l_exists_count = l_found_count) then
              exit;
            end if;
          END IF;
        exception
         when others then
           dbms_output.put_line(l_tab_columns_rec(j).table_name||'.'||l_tab_columns_rec(j).column_name||' : '||SQLERRM||' : '||SQLCODE);
           dbms_output.put_line(query_str);
           dbms_output.put_line('');
           /*raise*/
        end;
      END LOOP;
  end if;
 
END;

Похожие записи:

Categories: oracle, SQL Tags: , ,
  1. maart
    19 Сентябрь 2011 в 10:32 | #1

    Можно сделать небольшую оптимизацию скрипту по количеству элементов в цикле:

    l_str_length number;
    l_dummy      number;
    is_number    number(1);
    begin
      l_str_length := length(i_str);
     
      begin
          l_dummy   := to_number(i_str);
          is_number := 0;
      exception
          when others then
              is_number := 1;
      end;
     
      FOR t IN (select table_name, column_name
                  FROM all_tab_columns a
                 where owner = i_owner
                  and a.DATA_LENGTH >= l_str_length
                  and (a.data_type = ’VARCHAR2′ or
                    (is_number = 1 and a.data_type = ’NUMBER’))) 
      LOOP
    
  2. maart
    19 Сентябрь 2011 в 10:34 | #2

    ошибся в коде
    вместо «is_number := 0;» нужно конечно использовать «is_number := 1;» и наоборот.

  3. 19 Сентябрь 2011 в 10:57 | #3

    @maart
    мне проще закоментировать ненужный тип в строке

    and a.data_type in ('NUMBER', 'VARCHAR2')

    Но конечно, кому как удобно.

  4. maart
    19 Сентябрь 2011 в 11:13 | #4

    rudev :

    @maart
    мне проще закоментировать ненужный тип в строке
    1and a.data_type in ('NUMBER', 'VARCHAR2')
    Но конечно, кому как удобно.

    Я написал процедуру в своем пакете с утилитами, и в зависимости от входных параметров применяется разная логика поиска. Из неё и кусочек кода приложил.

    Например, добавил ещё два параметра. Первый отвечает за операнд «=» или «like ‘%i_str%'». Второй отвечает за регистр букв — учитывать или не учитывать.

  5. sunsbaby
    16 Ноябрь 2012 в 12:07 | #5

    Maart, приветствую! Очень нужен такой полезный скриптец — поиск заданного значения во всех таблицах и поиск объектов, которые сожержат, например заданное название столбца. Можешь, плиз, поделиться скриптами, от начала и до конца. Указанные здесь не срабатывают — 1 -й зависает напрочь, а твою оптимизацию не совсем понимаю…
    Заранее спасибо!

  6. sunsbaby
    16 Ноябрь 2012 в 12:08 | #6

    P.S. Для Oracle …

  7. 19 Ноябрь 2012 в 10:43 | #7

    Добавил второй вариант, работает быстрее.

  8. sunsbaby
    20 Ноябрь 2012 в 12:03 | #8

    Привет! Спасибо большое за оперативность — даже не ожидала такого скорого ответа! Единственное но… почему-то у меня оба этих скрипта виснут — я уж минут через 15 прерываю выполнение — надоедает ждать…
    Ты можешь, их, плиз, как-то оптимизировать?
    Буду тебе крайне признательна и благодарна!!! ;)

  9. 20 Ноябрь 2012 в 14:23 | #9

    @sunsbaby
    По большой схеме будет работать долго. У меня, например, отрабатывает около 1 часа.
    Для оптимизации можно ограничить названия таблиц, если примерно известно в каких лежат данные.

    and table_name like 'EMP%'
    select table_name
          ,column_name
          ,data_type
    FROM all_tab_columns a
    where owner = 'SCOTT'
          and a.data_length >= 5
          and (a.data_type = 'VARCHAR2' or a.data_type = 'NUMBER')
          and table_name like 'EMP%'

  10. 20 Ноябрь 2012 в 14:33 | #10

    Чуток подправил вариант2, добавил параметр

      -- При каком количестве найденные совпадений
      -- прекращать поиск
      l_found_count  NUMBER := 1
    

  11. sunsbaby
    20 Ноябрь 2012 в 16:10 | #11

    @rudev
    Спасибо огромнейшее! Ещё маленький глупый вопросик… У меня отработал 2-й вриант, но в рез-те тока написал «anonymous block completed» …а где же сам ответ посмотреть можно? :))
    P.S. готова тебя расцеловать (если тебя это интересует…….) ;) :))

  12. 20 Ноябрь 2012 в 16:47 | #12

    @sunsbaby
    В PL/SQL Developer можно просмотреть так:


    Если в SQL-PLUS, то раскомментировать первую строку:

    SET SERVEROUTPUT ON SIZE 1000000
    

  13. sunsbaby
    20 Ноябрь 2012 в 17:17 | #13

    @rudev
    A если Oracle SQL?

  14. sunsbaby
    20 Ноябрь 2012 в 17:29 | #14

    P.S. Может это как-то преобразовать в процедуру или функцию? :)

  15. 20 Ноябрь 2012 в 17:33 | #15

    @sunsbaby
    Для SQL Developer

  16. sunsbaby
    20 Ноябрь 2012 в 17:42 | #16

    Ура! Получилось! ТЫ супер-пупер программер!!!! :)

  17. Vadim
    10 Июнь 2013 в 11:11 | #17

    Здравствуйте, уважаемый
    Очень нужен этот полезный скриптец – поиск заданного значения во всех таблицах и поиск объектов, которые содержат, например заданное название столбца.
    Может, поделитесь скриптами, от начала и до конца.
    Заранее благодарю,
    Вадим

  18. 11 Июнь 2013 в 11:39 | #18

    Все, что вам надо, уже есть в посте.
    поиск заданного значения во всех таблицах — это вариант1 и вариант2
    поиск объектов, которые содержат, например заданное название столбца — таблица all_tab_columns

  19. Dmitro
    24 Июнь 2015 в 13:19 | #19

    Респект за скрипт, работает, пригодился! Переслал коллегам.

  1. Пока что нет уведомлений.