Danh sách các khóa ngoại và các bảng họ tham chiếu


142

Tôi đang cố gắng tìm một truy vấn sẽ trả về cho tôi một danh sách các khóa ngoại cho một bảng và các bảng và cột mà chúng tham chiếu. Tôi đi được nửa đường với

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'

Nhưng tôi vẫn cần biết bảng nào và khóa chính được tham chiếu bởi khóa này. Làm thế nào tôi có được điều đó?


Câu trả lời @MenelaosVergis đã làm nó tốt cho tôi, một cách dễ dàng - stackoverflow.com/a/15364469/1579667
Benj

Câu trả lời:


229

Khóa chính được tham chiếu được mô tả trong các cột r_ownerr_constraint_namecủa bảng ALL_CONSTRAINTS. Điều này sẽ cung cấp cho bạn thông tin bạn muốn:

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
Chỉ cần một lưu ý, mã ở trên không tính đến Khóa ngoại tổng hợp. Tham khảo câu trả lời dưới đây của @Dougman về cách hạch toán Khóa tổng hợp.
xkrz

2
@xkrz tổng hợp các khóa ngoại, như trong khóa ngoại được xác định trên nhiều cột? Tôi không thấy làm thế nào họ sẽ không được tính đến bởi các truy vấn trên!
Vincent Malgrat

1
@VincentMalgrat, xin lỗi, lỗi của tôi. Tôi đã cố gắng sử dụng mã của bạn để liệt kê "Tên bảng + Tên cột" được giới thiệu thay vì tên ràng buộc và đó không phải là mã của bạn.
xkrz

1
Điều đó làm phiền tôi rằng c.owner không phải là cột đầu tiên. Khác hơn là xuất sắc :)
roshan

1
@roshan Bây giờ bạn đề cập đến nó, thứ tự cột cảm thấy hơi kỳ lạ :) Rõ ràng năm năm trước tôi đã không nghĩ rằng câu trả lời này sẽ được nhiều người xem!
Vincent Malgrat

32

Thử cái này:

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

3
Không hoàn toàn rõ ràng OP thực sự muốn làm gì (với tôi) nhưng câu trả lời này đối với tôi hoạt động hoàn hảo (và đơn giản hơn) để trả lời điều này: "Làm thế nào để tôi nhận được các khóa ngoại tham chiếu đến một bảng cụ thể mà tôi chỉ định, trong Oracle? ". Với ràng buộc, tôi có thể phân tích. Mẹo: thêm "chủ sở hữu = 'MY_SCHema_HERE'" để làm rõ kết quả. Rất tốt.
Diego1974

21

Đây là một kịch bản đa năng mà chúng tôi sử dụng rất tiện dụng.

Lưu nó đi để bạn có thể thực hiện nó trực tiếp (@ fkeys.sql). Nó sẽ cho phép bạn tìm kiếm theo Chủ sở hữu và bảng Phụ huynh hoặc Trẻ em và hiển thị các mối quan hệ khóa ngoài. Tập lệnh hiện tại thực hiện hoàn toàn spool thành C: \ SQLRPTS, do đó bạn sẽ cần tạo thư mục thay đổi dòng đó thành thứ bạn muốn sử dụng.

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

Điều này sẽ đi theo hệ thống phân cấp của các khóa ngoại cho một bảng và cột nhất định và trả về các cột từ con và cháu, và tất cả các bảng con cháu. Nó sử dụng các truy vấn phụ để thêm r_table_name và r_column_name vào user_constraint, sau đó sử dụng chúng để kết nối các hàng.

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

Đây là một giải pháp khác. Sử dụng chế độ xem mặc định của sys rất chậm (khoảng 10 giây trong tình huống của tôi). Tốc độ này nhanh hơn nhiều (khoảng 0,5 giây).

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

Điều này không làm việc cho tôi trong Oracle 10g. "_CURRENT_EDITION_OBJ"không được công nhận.
StilesCrisis

2
Xin chào, thay thế SYS."_CURRENT_EDITION_OBJ"bằng SYS.OBJ$. Nó sẽ chạy trên cả 10g và 11g. Và chắc chắn rằng bạn có đủ đặc quyền. Ngoài ra tôi đã thay đổi câu trả lời của tôi với SYS.OBJ$.
Ganbat Bayarbaatar

Làm cách nào để bao gồm lược đồ (OWNER) trong câu lệnh này (dưới dạng chuỗi hệ thống)?
Adam Mrozek

5

Nếu bạn cần tất cả các khóa ngoại của người dùng thì hãy sử dụng đoạn mã sau

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'

dựa trên mã Vincent Malgrat


Nó dường như không trả về các ràng buộc của Người dùng và chỉ trả về WRM $ _SNAPSHOT và WRM $ _DATABASE_INSTANCE bằng TABLE_NAME và R_TABLE_NAME.
instanceOfObject

5

Tôi biết rằng hơi muộn để trả lời nhưng dù sao tôi cũng trả lời, một số câu trả lời ở trên khá phức tạp do đó đây là một cách đơn giản hơn nhiều.

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
Điều này trả lại nhiều hàng trùng lặp cho tôi. Tôi đã thêm DISTINCT cho nó, và nó xóa nó đi.
Ray K.

1

Trong trường hợp một người muốn tạo các ràng buộc FK từ bảng môi trường UAT sang Live, hãy kích hoạt bên dưới truy vấn động .....

    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
Cố gắng giải thích mã của bạn một chút ... Chỉ cần đưa mã giống như làm bài tập về nhà.
CoderNeji

1

Phiên bản của tôi, theo ý kiến ​​khiêm tốn của tôi, dễ đọc hơn:

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
Để làm cho nó hoạt động, tôi đã phải thay đổi ::với :tablevớitabl
ZygD

Vâng, bạn là người cứng nhắc, tôi đã tạo ra nó bằng WinQuery và nhận dạng biến đang sử dụng :: thay vì : , như trong SQLDeveloper, nơi bạn chỉ phải sử dụng : để ghi chú một văn bản dưới dạng một biến. Xin lỗi nếu nó không quá rõ ràng.
Francisco M

1

Hơi muộn với anwser, nhưng tôi hy vọng câu trả lời của tôi hữu ích cho ai đó, người cần chọn khóa ngoại tổng hợp.

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

Tôi đã sử dụng mã dưới đây và nó phục vụ mục đích của tôi-

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

Hãy viết những gì bạn đã làm trong giải pháp của bạn. Cảm ơn bạn.
Leonid Glanz

@LeonidGlanz, Nó giống như những gì tôi đã làm trong giải pháp của mình NGOẠI TRỪ 'tên bảng', tôi không hiểu ý của bạn là gì ...
ALIRA

1
bạn có thể thay đổi user_constraintsđể all_constraintskhi cần thiết.
ALIRA

bạn cũng có thể loại bỏ mệnh đề where trong đó tên bảng được xem xét.
ALIRA

ràng buộc_type = 'R' lọc các ràng buộc để chỉ hiển thị các ràng buộc quan hệ.
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

Để tải UserTable (Danh sách các khóa ngoại và các bảng mà chúng tham chiếu)

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; 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.