รายการคีย์ต่างประเทศและตารางที่อ้างอิง


143

ฉันพยายามค้นหาคิวรีซึ่งจะส่งคืนรายการคีย์ต่างประเทศสำหรับตารางและตารางและคอลัมน์ที่อ้างอิง ฉันอยู่ที่นั่นครึ่งทางแล้ว

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

คำตอบ:


229

คีย์หลักอ้างอิงอธิบายไว้ในคอลัมน์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

1
เพียงทราบรหัสข้างต้นไม่ได้คำนึงถึงคีย์ต่างประเทศรวม อ้างถึงคำตอบด้านล่างโดย @Dougman เกี่ยวกับวิธีการบัญชีสำหรับคีย์คอมโพสิต
xkrz

2
@xkrz คีย์ต่างประเทศแบบผสมเช่นเดียวกับในคีย์ต่างประเทศที่กำหนดไว้ในหลายคอลัมน์? ฉันไม่เห็นว่าพวกเขาจะไม่นำมาพิจารณาโดยการค้นหาข้างต้น!
Vincent Malgrat

1
@VincentMalgrat ขอโทษด้วยความผิดพลาดของฉัน ฉันพยายามใช้รหัสของคุณเพื่อแสดงรายการ "TableName + ColumnName" ที่อ้างถึงแทนชื่อข้อ จำกัด และไม่ใช่สิ่งที่รหัสของคุณทำ
xkrz

1
มันทำให้ฉันรำคาญใจว่า c.owner ไม่ใช่คอลัมน์แรก อื่น ๆ กว่าที่ยอดเยี่ยมที่ :)
roshan

1
@roshan ทีนี้เมื่อเจ้าพูดถึงคำสั่งของคอลัมน์รู้สึกแปลก ๆ :) เห็นได้ชัดว่าห้าปีที่แล้วฉันไม่คิดว่าคำตอบนี้จะถูกมองโดยคนจำนวนมาก!
Vincent Malgrat

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

21

นี่คือสคริปต์อเนกประสงค์ที่เราใช้ซึ่งมีประโยชน์อย่างไม่น่าเชื่อ

บันทึกออกเพื่อให้คุณสามารถดำเนินการได้โดยตรง (@ 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$นอกจากนี้ผมเปลี่ยนคำตอบของฉันด้วย
Ganbat Bayarbaatar

วิธีรวม schema (OWNER) ในคำสั่งนี้ (เป็น string fe SYSTEM) ได้อย่างไร?
Adam Mrozek

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'

ตามรหัส Vincent Malgrat


ดูเหมือนจะไม่ส่งคืนข้อ จำกัด ของผู้ใช้และส่งคืน 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

ใช่คุณเข้มงวดฉันใช้ 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

กรุณาเขียนสิ่งที่คุณทำในการแก้ปัญหาของคุณ ขอบคุณ.
Leonid Glanz

@ LeonidGlanz มันเหมือนกับสิ่งที่ฉันได้ทำในการแก้ปัญหาของฉันยกเว้น 'ชื่อตาราง' ฉันไม่เข้าใจสิ่งที่คุณหมายถึง ...
ALIRA

1
คุณสามารถเปลี่ยนuser_constraintsไปall_constraintsตามความจำเป็น
ALIRA

คุณยังสามารถลบคำสั่งย่อยที่พิจารณาชื่อตารางได้ด้วย
ALIRA

constraint_type = 'R' กรองข้อ จำกัด เพื่อแสดงข้อ จำกัด ด้านความสัมพันธ์
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

สำหรับโหลด 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; 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.