Как запустить сценарий, созданный из другого сценария в базе данных Oracle? - PullRequest
1 голос
/ 12 апреля 2011

Кто-нибудь знает, как выполнить все строки, сгенерированные из следующего запроса, как сценарии самостоятельно?

select 'DROP TABLE '||table_name||' CASCADE CONSTRAINTS;' from user_tables;

Что я в основном пытаюсь сделать, это удалить все пользовательские таблицы и ограниченияна моей БД (это оракул).Вывод, который я получаю, правильный, но я хочу знать, как бы я выполнял все строки без копирования / вставки.

Кроме того, есть ли более эффективный способ удаления всех таблиц (включая ограничения)?

Ответы [ 4 ]

4 голосов
/ 12 апреля 2011
begin
  for i in (select table_name from user_tables)
  loop
    execute immediate ('drop table ' || i.table_name || ' cascade constraints');
  end loop;
end;
/

Джастин Кейв поднял отличную мысль: ниже будут отброшены таблицы в схеме пользователя, начиная с самых внешних ветвей иерархии зависимостей, предполагая, что все внешние ключи ссылаются на первичный ключ, а не на уникальное ограничение.Таблицы без первичных ключей будут удалены последними.

begin
  for i in (select parent_table, max(tree_depth) as tree_depth
              from (select parent.table_name as parent_table,
                           child.constraint_name as foreign_key, 
                           child.table_name as child_table,
                           LEVEL AS TREE_DEPTH
                      from (select table_name, constraint_name
                              from USER_constraints
                             where constraint_type = 'P'
                           ) parent 
                           LEFT JOIN
                           (SELECT TABLE_NAME, CONSTRAINT_NAME, 
                                   r_constraint_name
                              FROM USER_CONSTRAINTS
                             WHERE CONSTRAINT_TYPE = 'R') child
                              on parent.constraint_name = 
                                    child.r_constraint_name
                           CONNECT BY NOCYCLE 
                             (PRIOR CHILD.TABLE_NAME = PARENT.TABLE_NAME)
                   UNION
                   select DT.table_name as parent_table,
                          NULL AS FOREIGN_KEY, NULL AS CHILD_TABLE,
                          0 AS TREE_DEPTH
                     FROM USER_TABLES DT
                    WHERE TABLE_NAME NOT IN
                          (SELECT TABLE_NAME
                             FROM USER_CONSTRAINTS
                            WHERE CONSTRAINT_TYPE = 'P')
                   )
             group by parent_table
             order by 2 desc
           )
  loop
    execute immediate ('drop table ' || i.parent_table || 
                       ' cascade constraints');
  end loop;
end;
/
3 голосов
/ 12 апреля 2011

Быстрое и грязное решение было бы сделать что-то вроде

FOR x IN (SELECT * FROM user_tables)
LOOP
  BEGIN
    EXECUTE IMMEDIATE 'DROP TABLE ' || x.table_name || 
                        ' CASCADE CONSTRAINTS';
  EXCEPTION
    WHEN others THEN
      dbms_output.put_line( 'Failed to drop ' || x.table_name ); 
  END;
END LOOP;

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

Более чистым вариантом будет написать иерархический запрос к словарю данных, чтобы получить дочерние таблицы, родителей этих детей, бабушек и дедушек и т. Д. И пройтись по дереву, чтобы отбросить соответствующие объекты. Это должно избежать ошибок, но потребует немного больше работы для кодирования.

1 голос
/ 12 апреля 2011

Обычно при удалении таблиц более эффективно использовать оператор truncate .

Вы можете выполнять динамические сценарии, используя команду немедленного выполнения

1 голос
/ 12 апреля 2011

execute immediate - передать сгенерированную строку

...