Liste der Fremdschlüssel und der Tabellen, auf die sie verweisen


142

Ich versuche, eine Abfrage zu finden, die mir eine Liste der Fremdschlüssel für eine Tabelle und der Tabellen und Spalten zurückgibt, auf die sie verweisen. Ich bin auf halbem Weg mit

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'

Ich muss jedoch noch wissen, auf welche Tabelle und welchen Primärschlüssel dieser Schlüssel verweist. Wie würde ich das bekommen?


@ MenelaosVergis Antwort hat es gut für mich gemacht, leicht - stackoverflow.com/a/15364469/1579667
Benj

Antworten:


229

Der referenzierte Primärschlüssel wird in den Spalten r_ownerund r_constraint_namein der Tabelle beschrieben ALL_CONSTRAINTS. Dadurch erhalten Sie die gewünschten Informationen:

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

1
Nur eine Anmerkung, der obige Code berücksichtigt keine zusammengesetzten Fremdschlüssel. In der folgenden Antwort von @Dougman erfahren Sie, wie Sie Composite Key berücksichtigen.
xkrz

2
@xkrz zusammengesetzte Fremdschlüssel, wie im Fremdschlüssel, der in mehreren Spalten definiert ist? Ich sehe nicht ein, wie sie bei der obigen Abfrage nicht berücksichtigt würden!
Vincent Malgrat

1
@ VincentMalgrat, entschuldige, mein Fehler. Ich habe versucht, Ihren Code zu verwenden, um den referenzierten "Tabellennamen + Spaltenname" anstelle des Einschränkungsnamens aufzulisten, und es war nicht das, was Ihr Code tut.
xkrz

1
Es stört mich, dass c.owner nicht die erste Spalte ist.
Davon abgesehen

1
@roshan Nun, da Sie es erwähnen, fühlt sich die Spaltenreihenfolge etwas seltsam an :) Offensichtlich hätte ich vor fünf Jahren nicht gedacht, dass diese Antwort von so vielen gesehen werden würde!
Vincent Malgrat

32

Versuche dies:

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

3
Es ist nicht ganz klar, was das OP wirklich tun wollte (für mich), aber diese Antwort für mich funktioniert perfekt (und es ist einfacher), dies zu beantworten: "Wie erhalte ich Fremdschlüssel, die auf eine bestimmte Tabelle verweisen, die ich in Oracle angegeben habe? ". Mit Einschränkungsname kann ich dann meine Analyse durchführen. Tipp: Fügen Sie "owner = 'MY_SCHEMA_HERE'" hinzu, um die Ergebnisse zu verdeutlichen. Sehr gut.
Diego

21

Hier ist ein Allzweck-Skript, das wir verwenden und das unglaublich praktisch war.

Speichern Sie es, damit Sie es direkt ausführen können (@ fkeys.sql). Sie können nach Eigentümer und entweder in der übergeordneten oder untergeordneten Tabelle suchen und Fremdschlüsselbeziehungen anzeigen. Das aktuelle Skript spoolt explizit in C: \ SQLRPTS, sodass Sie diesen Ordner erstellen müssen, um diese Zeile in etwas zu ändern, das Sie verwenden möchten.

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

Dadurch wird die Hierarchie der Fremdschlüssel für eine bestimmte Tabelle und Spalte durchlaufen und Spalten von Kind und Enkel sowie alle untergeordneten Tabellen zurückgegeben. Es verwendet Unterabfragen, um r_table_name und r_column_name zu user_constraints hinzuzufügen, und verwendet sie dann, um Zeilen zu verbinden.

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

Hier ist eine andere Lösung. Die Verwendung der Standardansichten von sys ist so langsam (ca. 10 Sekunden in meiner Situation). Dies ist viel schneller als das (ca. 0,5 s).

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 */;

Dies funktioniert bei mir in Oracle 10g nicht. "_CURRENT_EDITION_OBJ"wird nicht erkannt.
StilesCrisis

2
Hallo, ersetze SYS."_CURRENT_EDITION_OBJ"durch SYS.OBJ$. Es würde sowohl auf 10g als auch auf 11g laufen. Und stellen Sie sicher, dass Sie genügend Privilegien haben. Auch ich habe meine Antwort mit geändert SYS.OBJ$.
Ganbat Bayarbaatar

Wie kann man ein Schema (OWNER) in diese Anweisung aufnehmen (als Zeichenfolge zB SYSTEM)?
Adam Mrozek

5

Wenn Sie alle Fremdschlüssel des Benutzers benötigen, verwenden Sie das folgende Skript

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'

basierend auf Vincent Malgrat Code


Es scheint keine Benutzereinschränkungen zurückzugeben und gibt nur WRM $ _SNAPSHOT und WRM $ _DATABASE_INSTANCE in TABLE_NAME und R_TABLE_NAME zurück.
instanceOfObject

5

Ich weiß, dass es etwas spät ist zu antworten, aber lassen Sie mich trotzdem antworten. Einige der obigen Antworten sind ziemlich kompliziert, daher ist hier eine viel einfachere Einstellung.

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
Dies ergab für mich mehrere doppelte Zeilen. Ich habe DISTINCT hinzugefügt und es hat es geklärt.
Ray K.

1

Wenn Sie FK-Einschränkungen von der UAT-Umgebungstabelle zu Live erstellen möchten, feuern Sie unterhalb der dynamischen Abfrage .....

    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
Versuchen Sie, Ihren Code ein wenig zu erklären ... Nur Code zu geben ist eher wie Hausaufgaben zu machen.
CoderNeji

1

Meine Version ist meiner bescheidenen Meinung nach lesbarer:

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
Damit es funktioniert, musste ich mich ::mit :und tablemit änderntabl
ZygD

Ja, du hast rigth, ich habe es mit WinSQL und die variable Erkennung verwendet :: statt : wie in sqldeveloper, wo man nur verwenden müssen : einen Text als Variable zu beachten. Entschuldigung, wenn es nicht so klar war.
Francisco M

1

Es ist etwas spät zu antworten, aber ich hoffe, meine Antwort war nützlich für jemanden, der zusammengesetzte Fremdschlüssel auswählen muss.

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

Ich habe den folgenden Code verwendet und er hat meinen Zweck erfüllt.

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

Bitte schreiben Sie, was Sie in Ihrer Lösung getan haben. Danke dir.
Leonid Glanz

@LeonidGlanz, es ist genau das gleiche, was ich in meiner Lösung getan habe, AUSSER dem 'Tabellennamen', ich verstehe nicht was du meinst ...
ALIRA

1
Sie können das user_constraintsnach all_constraintsBedarf ändern .
ALIRA

Sie können auch die where-Klausel entfernen, in der der Tabellenname berücksichtigt wird.
ALIRA

Einschränkungsart = 'R' filtert die Einschränkungen, um nur Beziehungsbeschränkungen anzuzeigen.
ALIRA

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

Für Load UserTable (Liste der Fremdschlüssel und der Tabellen, auf die sie verweisen)

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; 
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.