Уважаемые подписчики! Большое спасибо всем, кто откликнулся на мою просьбу как-то прокомментировать работу рассылки. Тем из вас, кто писал в гостевую, я постарался ответить. Остальным, возможно, еще отвечу подробнее. Вероятно, в одном из следующих выпусков подведу и формальные итоги. Пока же прокомментирую полученные отзывы так.
Большинство ответивших считает, что выпуски, посвященные формальному синтаксису, не нужны. Тем не менее, они изредка будут выходить, хотя бы потому, что представленные в документации синтаксические диаграммы во многих случаях неудобно использовать.
Рассылка не предназначалась для начинающих. Но, я собираюсь опубликовать серию выпусков об основных концепциях Oracle, основных задачах администрирования и способах их решения.
Рассылка никогда не станет коммерческой или платной. Если вы, однако, очень хотите срочно заказать авторский материал или перевод по какой-то теме, связанной с СУБД Oracle, и готовы оплатить эту работу - шлите соответствующее письмо мне по электронной почте. Возможно, мы договоримся о приемлемых условиях сотрудничества.
Этот выпуск посвящен поиску всех отношений главная-подчиненная между таблицами базы данных. Последний раз Том Кайт вернулся к этому вопросу 10 января 2003 года. Выпуск выходит намного позже обещанного, но тому были свои причины, о которых можно почитать здесь.
Том!
Не мог бы ты объяснить, как получить список всех отношений главная-подчиненная
между таблицами базы данных.
В списке сначала должны идти таблицы, не являющиеся подчиненными, а в конце - не имеющие подчиненных.
Например,
Главная Подчиненная ---------------------------------------------------------------- BDP_INFO BAA CONTR ABP CONTR B_INCE CONTR BDP_INFO
Таблица BDP_INFO является главной по отношению к BAA, и одновременно подчиненной для CONTR. Поэтому список должен иметь следующий вид:
Contr ---------> BDP_info BDP_info ------> BAA ...
Такой список надо построить для всех таблиц, к которым имеет доступ данный пользователь.
Если НЕТ требований целостности, ссылающихся на ту же таблицу:
create table emp (empno int primary key, mgr int references emp(empno));
подойдет следующее решение:
Для упрощения решения необходимо использовать временную таблицу -- нельзя выполнять запрос connect by по соединению, поэтому необходимо скопировать user_constraints:
tkyte@TKYTE816> create table p (x int primary key);
Table created.
tkyte@TKYTE816> create table c1 (x primary key references p);
Table created.
tkyte@TKYTE816> create table c2 (x primary key references c1);
Table created.
tkyte@TKYTE816> create table c3 (x primary key references c2);
Table created.
tkyte@TKYTE816> create table c4 (x primary key references c2);
Table created.
tkyte@TKYTE816> create global temporary table temp_constraints
2 as
3 select a.table_name,
4 a.constraint_name pkey_constraint,
5 b.constraint_name fkey_constraint,
6 b.r_constraint_name
7 from user_constraints a, user_constraints b
8 where 1=0
9 /
Table created.
tkyte@TKYTE816> alter table temp_constraints modify fkey_constraint NULL;
Table altered.
tkyte@TKYTE816> delete from temp_constraints;
0 rows deleted.
tkyte@TKYTE816> insert into temp_constraints
2 select table_name, constraint_name, null, null from user_constraints where constraint_type
3 = 'P';
5 rows created.
tkyte@TKYTE816> insert into temp_constraints
2 select a.table_name,
3 a.constraint_name pkey_constraint,
4 b.constraint_name fkey_constraint,
5 b.r_constraint_name
6 from user_constraints a, user_constraints b
7 where a.table_name = b.table_name
8 and a.constraint_type = 'P'
9 and b.constraint_type = 'R'
10 /
4 rows created.
tkyte@TKYTE816> column table_name format a2
tkyte@TKYTE816> select * from temp_constraints;
TA PKEY_CONSTRAINT FKEY_CONSTRAINT
R_CONSTRAINT_NAME
-- ------------------------------ ------------------------------
------------------------------
C1 SYS_C004927
C2 SYS_C004929
C3 SYS_C004931
C4 SYS_C004933
P SYS_C004926
C1 SYS_C004927 SYS_C004928 SYS_C004926
C2 SYS_C004929 SYS_C004930 SYS_C004927
C3 SYS_C004931 SYS_C004932 SYS_C004929
C4 SYS_C004933 SYS_C004934 SYS_C004929
9 rows selected.
tkyte@TKYTE816> column table_name format a10
tkyte@TKYTE816> select rpad('*', (level-1)*2, '*') || table_name table_name
2 from temp_constraints
3 start with fkey_constraint is null
4 connect by prior pkey_constraint = r_constraint_name
5 /
TABLE_NAME
----------
C1
**C2
****C3
****C4
C2
**C3
**C4
C3
C4
P
**C1
****C2
******C3
******C4
14 rows selected.
Том, я был бы очень благодарен, если бы ты подсказал, как написать сценарий, выбирающий операторы ЯОД, CREATE TABLE и т.д. для всех доступных объектов из словаря данных.
Я знаю, что могу получить эту информацию с помощью утилиты EXP, но я хотел бы по-своему сформатировать результат.
Если я не ошибаюсь, где-то на сайте Oracle есть похожий сценарий. Не пришлете ссылку?
Лично я о таком сценарии ничего не знаю -- я использую утилиту EXP (на самом деле, я использую утилиту exp ТОЛЬКО для получения информации о чужих схемах, поскольку я всегда поддерживаю свои сценарии в актуальном состоянии и выбирать операторы ЯОД из базы мне не нужно)...
В любом случае, в версии 9i есть соответствующая возможность:
scott@ORA9I.WORLD> select dbms_metadata.get_ddl('TABLE', 'EMP') from dual;
DBMS_METADATA.GET_DDL('TABLE','EMP')
--------------------------------------------------------------------------------
CREATE TABLE "SCOTT"."EMP"
( "EMPNO" NUMBER(4,0) NOT NULL ENABLE,
"ENAME" VARCHAR2(10),
"JOB" VARCHAR2(9),
"MGR" NUMBER(4,0),
"HIREDATE" DATE,
"SAL" NUMBER(7,2),
"COMM" NUMBER(7,2),
"DEPTNO" NUMBER(2,0),
CONSTRAINT "EMP_PK" PRIMARY KEY ("EMPNO")
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
STORAGE(INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0
FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS" ENABLE,
CONSTRAINT "EMP_FK_EMP" FOREIGN KEY ("MGR")
REFERENCES "SCOTT"."EMP" ("EMPNO") ENABLE NOVALIDATE,
CONSTRAINT "EMP_FK_DEPT" FOREIGN KEY ("DEPTNO")
REFERENCES "SCOTT"."DEPT" ("DEPTNO") ENABLE NOVALIDATE
) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 LOGGING
STORAGE(INITIAL 524288 NEXT 524288 MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0
FREELISTS 1 FREELIST GROUPS 1 BUFFER_POOL DEFAULT) TABLESPACE "USERS"
Я попытался использовать ваше решение и получил следующее сообщение об ошибке.
ERROR at line 2: ORA-01436: CONNECT BY loop in user data
И еще, нельзя ли указать условие в иерархическом запросе, например, чтобы выбирать информацию только о таблицах, имена которых начинаются с 'HEDGE'
Нет ли в вашей схеме внешних ключей, ссылающихся на ту же таблицу? Если да, представленное решение не сработает (как я и упоминал в ответе)...
Да, а условия в запрос с конструкцией connect by добавить можно:
where tname like 'HEDGE%' ... start with tname like 'HEDGE%' ... connect by prior ..... and tname like 'HEDGE%' ...
Но может оказаться проще сначала скопировать информацию по таблицам с именами типа HEDGE%. Но напомню, что если таблица ссылается сама на себя, получится цикл connect by, и представлденное решение НЕ сработает.
Сначала ты вставляешь в таблицу имена таблиц и ограничений типа 'P', а что ты вставляешь второй раз?
Сначала я вставляю первичные ключи (constraint_type = 'P')
Затем я вставляю информацию о первичных ключах и ссылающихся на них внешних ключах (constraint_type = 'R')
Том, мне кажется, что исключить внешние ключи, ссылающиеся на первичный ключ той же таблицы, несложно:
select a.table_name,
a.constraint_name pkey_constraint,
b.constraint_name fkey_constraint,
b.r_constraint_name
from user_constraints a, user_constraints b
where a.table_name = b.table_name
and a.constraint_type = 'P'
and b.constraint_type = 'R'
and a.constraint_name != b.r_constraint_name
/
... если я ничего не упустил, конечно.
Твой запрос не выбирает внешние ключи, ссылающиеся на другие уникальные ключи таблицы, а не на первичный. Ты считаешь, что так задавать внешние ключи неправильно?
Ну, почему же "неправильно" - просто такое нечасто встречается. Можно легко учесть эту ситуацию, добавив функцию decode по полю a.constraint_type, которая будет делать значения P и U "одинаковыми".
Оригинал обсуждения этого вопроса можно найти здесь.
Copyright © 2002 Oracle Corporation
Результаты опроса подписчиков. Возможно, первый из серии авторских выпусков, посвященных индексам. Или перевод очередного блестящего ответа Тома Кайта... Следите за новостями на сайте проекта Open Oracle.
С наилучшими пожеланиями,
В.К.
|
|