【问题标题】:List of foreign keys and the tables they reference in Oracle DB外键列表及其在 Oracle DB 中引用的表
【发布时间】:2010-12-16 08:16:27
【问题描述】:

我试图找到一个查询,它将返回一个表的外键列表以及它们引用的表和列。我已经完成了一半

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'

但是我仍然需要知道这个键引用了哪个表和主键。我怎么会得到它?

【问题讨论】:

标签: oracle metadata database-metadata


【解决方案1】:

引用的主键在表ALL_CONSTRAINTSr_ownerr_constraint_name 列中进行了描述。这将为您提供所需的信息:

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

【讨论】:

  • 请注意,上面的代码没有考虑复合外键。请参阅下面@Dougman 的回答,了解如何计算复合键。
  • @xkrz 复合外键,就像在多列上定义的外键一样?我看不出上面的查询如何不考虑它们!
  • @VincentMalgrat,抱歉,我的错误。我试图使用您的代码列出引用的“TableName+ColumnName”而不是约束名称,这不是您的代码所做的。
  • 令我困扰的是 c.owner 不是第一列。除了那优秀的:)
  • @roshan 既然你提到了,列的顺序感觉有点奇怪:)显然五年前我不会想到这个答案会被这么多人查看!
【解决方案2】:

我使用了下面的代码,它达到了我的目的-

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';

【讨论】:

    【解决方案3】:

    回答有点晚了,但我希望我的回答对需要选择复合外键的人有用。

    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'
    

    【讨论】:

      【解决方案4】:

      以我的拙见,我的版本更具可读性:

      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
      

      【讨论】:

      • 为了让它工作,我不得不把::改成:,把table改成tabl
      • 是的,你说得对,我是使用 WinSQL 实现的,变量识别是使用 :: 而不是 :,就像在 SQLDeveloper 中一样,您必须仅使用 : 将文本记为变量。抱歉,如果不是很清楚。
      【解决方案5】:

      如果想创建从 UAT 环境表到 Live 的 FK 约束,请在动态查询下方触发.....

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

      【讨论】:

      • 试着解释一下你的代码......只是给出代码更像是在做作业。
      【解决方案6】:

      用于加载用户表(外键列表及其引用的表)

      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; 
      

      【讨论】:

        【解决方案7】:
        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;
        

        【讨论】:

          【解决方案8】:
          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;
          

          【讨论】:

            【解决方案9】:

            我知道现在回答有点晚了,但还是让我回答吧,一些答案 上面很复杂,因此这里是一个更简单的方法。

            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'
            

            【讨论】:

            • 这为我返回了多个重复的行。我向它添加了 DISTINCT,它清除了它。
            【解决方案10】:
            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 ,这和我在解决方案中所做的一样除了“表名”,我不明白你的意思......
            • 您可以根据需要将user_constraints更改为all_constraints
            • 您也可以删除考虑表名的 where 子句。
            • constraint_type = 'R' 过滤约束以仅显示关系约束。
            【解决方案11】:

            试试这个:

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

            【讨论】:

            • 目前还不完全清楚 OP 真正想要做什么(对我而言),但 this 对我来说回答完美(而且更简单)回答这个问题:“我该怎么做获取引用我在 Oracle 中指定的特定表的外键?”。使用 constraint_name 我可以进行分析。提示:添加“owner='MY_SCHEMA_HERE'”以澄清结果。非常好。
            【解决方案12】:

            这是另一种解决方案。使用 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" 无法识别。
            • 您好,请将 SYS."_CURRENT_EDITION_OBJ" 替换为 SYS.OBJ$。它将在 10g 和 11g 上运行。并确保您有足够的特权。我也用SYS.OBJ$改变了我的答案。
            • 如何在此语句中包含架构(OWNER)(作为字符串 f.e. SYSTEM)?
            【解决方案13】:

            这将遍历给定表和列的外键层次结构,并从子表和孙表以及所有后代表返回列。它使用子查询将 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;
            

            【讨论】:

              【解决方案14】:

              如果您需要用户的所有外键,请使用以下脚本

              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 代码

              【讨论】:

              • 它似乎没有返回用户约束,只返回 TABLE_NAME 和 R_TABLE_NAME 中的 WRM$_SNAPSHOT 和 WRM$_DATABASE_INSTANCE。
              【解决方案15】:

              这是我们使用的通用脚本,非常方便。

              保存它,以便您可以直接执行它 (@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
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2011-06-30
                • 1970-01-01
                • 2023-01-31
                • 2015-10-24
                • 1970-01-01
                相关资源
                最近更新 更多