Список внешних ключей и таблиц, на которые они ссылаются в Oracle DB


144

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

SELECT a.table_name, 
       a.column_name, 
       a.constraint_name, 
       c.owner
FROM ALL_CONS_COLUMNS A, ALL_CONSTRAINTS C  
where A.CONSTRAINT_NAME = C.CONSTRAINT_NAME 
  and a.table_name=:TableName 
  and C.CONSTRAINT_TYPE = 'R'

Но мне все еще нужно знать, на какую таблицу и первичный ключ ссылается этот ключ. Как мне это получить?


Ответ @MenelaosVergis помог мне, легко - stackoverflow.com/a/15364469/1579667
Benj

Ответы:


233

Упомянутый первичный ключ описан в столбцах r_ownerи r_constraint_nameтаблице ALL_CONSTRAINTS. Это даст вам нужную информацию:

SELECT a.table_name, a.column_name, a.constraint_name, c.owner, 
       -- referenced pk
       c.r_owner, c_pk.table_name r_table_name, c_pk.constraint_name r_pk
  FROM all_cons_columns a
  JOIN all_constraints c ON a.owner = c.owner
                        AND a.constraint_name = c.constraint_name
  JOIN all_constraints c_pk ON c.r_owner = c_pk.owner
                           AND c.r_constraint_name = c_pk.constraint_name
 WHERE c.constraint_type = 'R'
   AND a.table_name = :TableName

2
Замечу, что приведенный выше код не учитывает составные внешние ключи. Обратитесь к ответу @Dougman ниже, чтобы узнать, как учитывать составной ключ.
xkrz

2
@xkrz составные внешние ключи, как в внешнем ключе, определенном в нескольких столбцах? Я не понимаю, как бы они не были учтены вышеуказанным запросом!
Винсент Мальграт,

1
@VincentMalgrat, извиняюсь за мою ошибку. Я пытался использовать ваш код для перечисления упомянутого «TableName + ColumnName» вместо имени ограничения, и это было не то, что делает ваш код.
xkrz

1
Меня беспокоит, что c.owner - не первая колонка. В остальном отлично :)
roshan

1
@roshan Теперь, когда вы упомянули об этом, порядок столбцов кажется немного странным :) Очевидно, пять лет назад я бы не подумал, что этот ответ увидят так много!
Винсент Мальграт

33

Попробуй это:

select * from all_constraints where r_constraint_name in (select constraint_name 
from all_constraints where table_name='YOUR_TABLE_NAME');

3
Не совсем понятно, что OP действительно хотел сделать (для меня), но этот ответ для меня работает идеально (и это проще), чтобы ответить на этот вопрос: «Как мне получить внешние ключи, ссылающиеся на конкретную таблицу, которую я указываю, в Oracle? ". Затем с помощью constraint_name я могу провести анализ. Совет: добавьте «owner = 'MY_SCHEMA_HERE'», чтобы уточнить результаты. Очень хорошо.
Diego1974

22

Вот универсальный сценарий, который мы использовали, и он оказался невероятно удобным.

Сохраните его, чтобы можно было выполнить напрямую (@ fkeys.sql). Это позволит вам искать по Владельцу и либо по родительской, либо по дочерней таблице, а также отображать отношения внешнего ключа. Текущий сценарий явно выполняет буферизацию в C: \ SQLRPTS, поэтому вам нужно будет создать эту папку для изменения этой строки на то, что вы хотите использовать.

REM ########################################################################
REM ##
REM ##   fkeys.sql
REM ##
REM ##   Displays the foreign key relationships
REM ##
REM #######################################################################

CLEAR BREAK
CLEAR COL
SET LINES 200
SET PAGES 54
SET NEWPAGE 0
SET WRAP OFF
SET VERIFY OFF
SET FEEDBACK OFF

break on table_name skip 2 on constraint_name on r_table_name skip 1

column CHILDCOL format a60 head 'CHILD COLUMN'
column PARENTCOL format a60 head 'PARENT COLUMN'
column constraint_name format a30 head 'FK CONSTRAINT NAME'
column delete_rule format a15
column bt noprint
column bo noprint

TTITLE LEFT _DATE CENTER 'FOREIGN KEY RELATIONSHIPS ON &new_prompt' RIGHT 'PAGE:'FORMAT 999 SQL.PNO SKIP 2

SPOOL C:\SQLRPTS\FKeys_&new_prompt
ACCEPT OWNER_NAME PROMPT 'Enter Table Owner (or blank for all): '
ACCEPT PARENT_TABLE_NAME PROMPT 'Enter Parent Table or leave blank for all: '
ACCEPT CHILD_TABLE_NAME PROMPT 'Enter Child Table or leave blank for all: '

  select b.owner || '.' || b.table_name || '.' || b.column_name CHILDCOL,
         b.position,
         c.owner || '.' || c.table_name || '.' || c.column_name PARENTCOL,
         a.constraint_name,
         a.delete_rule,
         b.table_name bt,
         b.owner bo
    from all_cons_columns b,
         all_cons_columns c,
         all_constraints a
   where b.constraint_name = a.constraint_name
     and a.owner           = b.owner
     and b.position        = c.position
     and c.constraint_name = a.r_constraint_name
     and c.owner           = a.r_owner
     and a.constraint_type = 'R'
     and c.owner      like case when upper('&OWNER_NAME') is null then '%'
                                else upper('&OWNER_NAME') end
     and c.table_name like case when upper('&PARENT_TABLE_NAME') is null then '%'
                                else upper('&PARENT_TABLE_NAME') end
     and b.table_name like case when upper('&CHILD_TABLE_NAME') is null then '%'
                                else upper('&CHILD_TABLE_NAME') end
order by 7,6,4,2
/
SPOOL OFF
TTITLE OFF
SET FEEDBACK ON
SET VERIFY ON
CLEAR BREAK
CLEAR COL
SET PAGES 24
SET LINES 100
SET NEWPAGE 1
UNDEF OWNER

12

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

select distinct table_name, constraint_name, column_name, r_table_name, position, constraint_type 
from (
    SELECT uc.table_name, 
    uc.constraint_name, 
    cols.column_name, 
    (select table_name from user_constraints where constraint_name = uc.r_constraint_name) 
        r_table_name,
    (select column_name from user_cons_columns where constraint_name = uc.r_constraint_name and position = cols.position) 
        r_column_name,
    cols.position,
    uc.constraint_type
    FROM user_constraints uc
    inner join user_cons_columns cols on uc.constraint_name = cols.constraint_name 
    where constraint_type != 'C'
) 
start with table_name = 'MY_TABLE_NAME' and column_name = 'MY_COLUMN_NAME'  
connect by nocycle 
prior table_name = r_table_name 
and prior column_name = r_column_name;

8

Вот еще одно решение. Использование представлений sys по умолчанию очень медленное (около 10 секунд в моей ситуации). Это намного быстрее (примерно 0,5 с).

SELECT
    CONST.NAME AS CONSTRAINT_NAME,
    RCONST.NAME AS REF_CONSTRAINT_NAME,

    OBJ.NAME AS TABLE_NAME,
    COALESCE(ACOL.NAME, COL.NAME) AS COLUMN_NAME,
    CCOL.POS# AS POSITION,

    ROBJ.NAME AS REF_TABLE_NAME,
    COALESCE(RACOL.NAME, RCOL.NAME) AS REF_COLUMN_NAME,
    RCCOL.POS# AS REF_POSITION
FROM SYS.CON$ CONST
INNER JOIN SYS.CDEF$ CDEF ON CDEF.CON# = CONST.CON#
INNER JOIN SYS.CCOL$ CCOL ON CCOL.CON# = CONST.CON#
INNER JOIN SYS.COL$ COL  ON (CCOL.OBJ# = COL.OBJ#) AND (CCOL.INTCOL# = COL.INTCOL#)
INNER JOIN SYS.OBJ$ OBJ ON CCOL.OBJ# = OBJ.OBJ#
LEFT JOIN SYS.ATTRCOL$ ACOL ON (CCOL.OBJ# = ACOL.OBJ#) AND (CCOL.INTCOL# = ACOL.INTCOL#)

INNER JOIN SYS.CON$ RCONST ON RCONST.CON# = CDEF.RCON#
INNER JOIN SYS.CCOL$ RCCOL ON RCCOL.CON# = RCONST.CON#
INNER JOIN SYS.COL$ RCOL  ON (RCCOL.OBJ# = RCOL.OBJ#) AND (RCCOL.INTCOL# = RCOL.INTCOL#)
INNER JOIN SYS.OBJ$ ROBJ ON RCCOL.OBJ# = ROBJ.OBJ#
LEFT JOIN SYS.ATTRCOL$ RACOL  ON (RCCOL.OBJ# = RACOL.OBJ#) AND (RCCOL.INTCOL# = RACOL.INTCOL#)

WHERE CONST.OWNER# = userenv('SCHEMAID')
  AND RCONST.OWNER# = userenv('SCHEMAID')
  AND CDEF.TYPE# = 4  /* 'R' Referential/Foreign Key */;

У меня это не работает в Oracle 10g. "_CURRENT_EDITION_OBJ"нераспознан.
StilesCrisis

2
Привет, замените SYS."_CURRENT_EDITION_OBJ"на SYS.OBJ$. Он будет работать как на 10g, так и на 11g. И убедитесь, что у вас достаточно привилегий. Также я изменил свой ответ на SYS.OBJ$.
Ганбат Баярбаатар

Как включить схему (OWNER) в этот оператор (как строку fe SYSTEM)?
Адам Мрозек

5

Если вам нужны все внешние ключи пользователя, используйте следующий скрипт

SELECT a.constraint_name, a.table_name, a.column_name,  c.owner, 
       c_pk.table_name r_table_name,  b.column_name r_column_name
  FROM user_cons_columns a
  JOIN user_constraints c ON a.owner = c.owner
       AND a.constraint_name = c.constraint_name
  JOIN user_constraints c_pk ON c.r_owner = c_pk.owner
       AND c.r_constraint_name = c_pk.constraint_name
  JOIN user_cons_columns b ON C_PK.owner = b.owner
       AND  C_PK.CONSTRAINT_NAME = b.constraint_name AND b.POSITION = a.POSITION     
 WHERE c.constraint_type = 'R'

на основе кода Винсента Мальграта


Кажется, что он не возвращает пользовательские ограничения и возвращает только WRM $ _SNAPSHOT и WRM $ _DATABASE_INSTANCE в TABLE_NAME и R_TABLE_NAME.
instanceOfObject

5

Я знаю, что уже поздно отвечать, но позвольте мне все равно ответить, некоторые из приведенных выше ответов довольно сложны, поэтому здесь гораздо проще.

SELECT a.table_name child_table, a.column_name child_column, a.constraint_name, 
      b.table_name parent_table, b.column_name parent_column
  FROM all_cons_columns a
  JOIN all_constraints c ON a.owner = c.owner AND a.constraint_name = c.constraint_name
 join all_cons_columns b on c.owner = b.owner and c.r_constraint_name = b.constraint_name
 WHERE c.constraint_type = 'R'
   AND a.table_name = 'your table name'

1
Это вернуло мне несколько повторяющихся строк. Я добавил к нему DISTINCT, и он прояснил это.
Ray K.

1

Если кто-то хочет создать ограничения FK из таблицы среды UAT в Live, запускайте динамический запрос ниже .....

    SELECT 'ALTER TABLE '||OBJ.NAME||' ADD CONSTRAINT '||CONST.NAME||'     FOREIGN KEY ('||COALESCE(ACOL.NAME, COL.NAME)||') REFERENCES '
||ROBJ.NAME ||' ('||COALESCE(RACOL.NAME, RCOL.NAME) ||');'
FROM SYS.CON$ CONST
INNER JOIN SYS.CDEF$ CDEF ON CDEF.CON# = CONST.CON#
INNER JOIN SYS.CCOL$ CCOL ON CCOL.CON# = CONST.CON#
INNER JOIN SYS.COL$ COL  ON (CCOL.OBJ# = COL.OBJ#) AND (CCOL.INTCOL# =     COL.INTCOL#)
INNER JOIN SYS.OBJ$ OBJ ON CCOL.OBJ# = OBJ.OBJ#
LEFT JOIN SYS.ATTRCOL$ ACOL ON (CCOL.OBJ# = ACOL.OBJ#) AND (CCOL.INTCOL# =     ACOL.INTCOL#)

INNER JOIN SYS.CON$ RCONST ON RCONST.CON# = CDEF.RCON#
INNER JOIN SYS.CCOL$ RCCOL ON RCCOL.CON# = RCONST.CON#
INNER JOIN SYS.COL$ RCOL  ON (RCCOL.OBJ# = RCOL.OBJ#) AND (RCCOL.INTCOL# =     RCOL.INTCOL#)
INNER JOIN SYS.OBJ$ ROBJ ON RCCOL.OBJ# = ROBJ.OBJ#
LEFT JOIN SYS.ATTRCOL$ RACOL  ON (RCCOL.OBJ# = RACOL.OBJ#) AND     (RCCOL.INTCOL# = RACOL.INTCOL#)

WHERE CONST.OWNER# = userenv('SCHEMAID')
AND RCONST.OWNER# = userenv('SCHEMAID')
AND CDEF.TYPE# = 4 
AND OBJ.NAME = <table_name>;

1
Попробуйте немного объяснить свой код ... Просто дать код больше похоже на домашнее задание.
CoderNeji

1

Моя версия, по моему скромному мнению, более читабельна:

SELECT   PARENT.TABLE_NAME  "PARENT TABLE_NAME"
,        PARENT.CONSTRAINT_NAME  "PARENT PK CONSTRAINT"
,       '->' " "
,        CHILD.TABLE_NAME  "CHILD TABLE_NAME"
,        CHILD.COLUMN_NAME  "CHILD COLUMN_NAME"
,        CHILD.CONSTRAINT_NAME  "CHILD CONSTRAINT_NAME"
FROM     ALL_CONS_COLUMNS   CHILD
,        ALL_CONSTRAINTS   CT
,        ALL_CONSTRAINTS   PARENT
WHERE    CHILD.OWNER  =  CT.OWNER
AND      CT.CONSTRAINT_TYPE  = 'R'
AND      CHILD.CONSTRAINT_NAME  =  CT.CONSTRAINT_NAME 
AND      CT.R_OWNER  =  PARENT.OWNER
AND      CT.R_CONSTRAINT_NAME  =  PARENT.CONSTRAINT_NAME 
AND      CHILD.TABLE_NAME  = ::table -- table name variable
AND      CT.OWNER  = ::owner; -- schema variable, could not be needed

1
Чтобы заставить его работать, мне пришлось поменять ::с :и tableсtabl
ZygD 05

Да, вы правы, я сделал это с помощью WinSQL, а для распознавания переменных используется :: вместо :, как в SQLDeveloper, где вам нужно использовать только :, чтобы отметить текст как переменную. Извините, если это было не так ясно.
Francisco M

1

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

SELECT
    "C"."CONSTRAINT_NAME",
    "C"."OWNER" AS "SCHEMA_NAME",
    "C"."TABLE_NAME",
    "COL"."COLUMN_NAME",
    "REF_COL"."OWNER" AS "REF_SCHEMA_NAME",
    "REF_COL"."TABLE_NAME" AS "REF_TABLE_NAME",
    "REF_COL"."COLUMN_NAME" AS "REF_COLUMN_NAME"
FROM
    "USER_CONSTRAINTS" "C"
INNER JOIN "USER_CONS_COLUMNS" "COL" ON "COL"."OWNER" = "C"."OWNER"
 AND "COL"."CONSTRAINT_NAME" = "C"."CONSTRAINT_NAME"
INNER JOIN "USER_CONS_COLUMNS" "REF_COL" ON "REF_COL"."OWNER" = "C"."R_OWNER"
 AND "REF_COL"."CONSTRAINT_NAME" = "C"."R_CONSTRAINT_NAME"
 AND "REF_COL"."POSITION" = "COL"."POSITION"
WHERE "C"."TABLE_NAME" = 'TableName' AND "C"."CONSTRAINT_TYPE" = 'R'

1

Я использовал приведенный ниже код, и он послужил моей цели -

SELECT fk.owner, fk.table_name, col.column_name
FROM dba_constraints pk, dba_constraints fk, dba_cons_columns col
WHERE pk.constraint_name = fk.r_constraint_name
AND fk.constraint_name = col.constraint_name
AND pk.owner = col.owner
AND pk.owner = fk.owner
AND fk.constraint_type = 'R'   
AND pk.owner = sys_context('USERENV', 'CURRENT_SCHEMA') 
AND pk.table_name = :my_table
AND pk.constraint_type = 'P';

0
select d.table_name,

       d.constraint_name "Primary Constraint Name",

       b.constraint_name "Referenced Constraint Name"

from user_constraints d,

     (select c.constraint_name,

             c.r_constraint_name,

             c.table_name

      from user_constraints c 

      where table_name='EMPLOYEES' --your table name instead of EMPLOYEES

      and constraint_type='R') b

where d.constraint_name=b.r_constraint_name

Напишите, пожалуйста, что вы сделали в своем решении. Спасибо.
Леонид Гланц

@LeonidGlanz, это то же самое, что я сделал в своем решении, ЗА ИСКЛЮЧЕНИЕМ «имени таблицы», я не понимаю, что вы имеете в виду ...
АЛИРА

1
Вы можете изменить , user_constraintsчтобы all_constraintsв случае необходимости.
АЛИРА

также вы можете удалить предложение where, в котором учитывается имя таблицы.
АЛИРА

constraint_type = 'R' фильтрует ограничения, чтобы показать только ограничения отношения.
АЛИРА

0
SELECT a.table_name, a.column_name, a.constraint_name, c.owner, 
       -- referenced pk
       c.r_owner, c_pk.table_name r_table_name, c_pk.constraint_name r_pk
  FROM all_cons_columns a
  JOIN all_constraints c ON a.owner = c.owner
                        AND a.constraint_name = c.constraint_name
  JOIN all_constraints c_pk ON c.r_owner = c_pk.owner
                           AND c.r_constraint_name = c_pk.constraint_name
 WHERE c.constraint_type = 'R'
   AND a.table_name :=TABLE_NAME
   AND c.owner :=OWNER_NAME;

0
WITH reference_view AS
     (SELECT a.owner, a.table_name, a.constraint_name, a.constraint_type,
             a.r_owner, a.r_constraint_name, b.column_name
        FROM dba_constraints a, dba_cons_columns b
       WHERE  a.owner LIKE UPPER ('SYS') AND
          a.owner = b.owner
         AND a.constraint_name = b.constraint_name
         AND constraint_type = 'R'),
     constraint_view AS
     (SELECT a.owner a_owner, a.table_name, a.column_name, b.owner b_owner,
             b.constraint_name
        FROM dba_cons_columns a, dba_constraints b
       WHERE a.owner = b.owner
         AND a.constraint_name = b.constraint_name
         AND b.constraint_type = 'P'
         AND a.owner LIKE UPPER ('SYS')
         )
SELECT  
       rv.table_name FK_Table , rv.column_name FK_Column ,
       CV.table_name PK_Table , rv.column_name PK_Column , rv.r_constraint_name Constraint_Name 
  FROM reference_view rv, constraint_view CV
 WHERE rv.r_constraint_name = CV.constraint_name AND rv.r_owner = CV.b_owner;

0

Для загрузки UserTable (список внешних ключей и таблицы, на которые они ссылаются)

WITH

reference_view AS
     (SELECT a.owner, a.table_name, a.constraint_name, a.constraint_type,
             a.r_owner, a.r_constraint_name, b.column_name
        FROM dba_constraints a, dba_cons_columns b
       WHERE 
          a.owner = b.owner
         AND a.constraint_name = b.constraint_name
         AND constraint_type = 'R'),
constraint_view AS
     (SELECT a.owner a_owner, a.table_name, a.column_name, b.owner b_owner,
             b.constraint_name
        FROM dba_cons_columns a, dba_constraints b
       WHERE a.owner = b.owner
         AND a.constraint_name = b.constraint_name
         AND b.constraint_type = 'P'

         ) ,
usertableviewlist AS 
(
      select  TABLE_NAME  from user_tables  
) 
SELECT  
       rv.table_name FK_Table , rv.column_name FK_Column ,
       CV.table_name PK_Table , rv.column_name PK_Column , rv.r_constraint_name Constraint_Name 
  FROM reference_view rv, constraint_view CV , usertableviewlist UTable
 WHERE rv.r_constraint_name = CV.constraint_name AND rv.r_owner = CV.b_owner And UTable.TABLE_NAME = rv.table_name; 
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.