在Oracle ALL_CONSTRAINTS

时间:2019-03-29 12:10:21

标签: sql oracle check-constraints

考虑此表定义:

CREATE TABLE foo (
  a int not null,              -- Implicit not null constraint
  b int check (b is not null), -- Explicit not null constraint
  c int check (c > 1)          -- Explicit constraint
);

我想发现所有显式检查约束,即用户使用CHECK语法在其DDL语句中定义的约束。这些约束可以命名也可以不命名。在上面的示例中,它们没有命名。如何仅发现“显式”检查约束,而忽略隐式约束?

例如当我查询ALL_CONSTRAINTS时:

SELECT *
FROM all_constraints
WHERE constraint_type = 'C'
AND table_name = 'FOO';

我看不到任何方法来区分显性/隐性:

CONSTRAINT_NAME   SEARCH_CONDITION   GENERATED
---------------------------------------------------
SYS_C00120656     "A" IS NOT NULL    GENERATED NAME
SYS_C00120657     b is not null      GENERATED NAME
SYS_C00120658     c > 1              GENERATED NAME

3 个答案:

答案 0 :(得分:3)

我当然可以使用精确的"COLUMN_NAME" IS NOT NULL语法(包括双引号)来启发某人的可能性:

SELECT *
FROM all_constraints
WHERE constraint_type = 'C'
AND table_name = 'FOO'
AND search_condition_vc NOT IN (
  SELECT '"' || column_name || '" IS NOT NULL'
  FROM all_tab_cols
  WHERE table_name = 'FOO'
  AND nullable = 'N'
);

这给了我想要的结果:

CONSTRAINT_NAME   SEARCH_CONDITION   GENERATED
---------------------------------------------------
SYS_C00120657     b is not null      GENERATED NAME
SYS_C00120658     c > 1              GENERATED NAME

我在这里回答这个问题,因为这对于某些人来说可能已经足够了,但是我真的希望有一个更可靠的解决方案。

答案 1 :(得分:2)

想法:您可以将表格与其对应的“影子”进行比较。 CREATE TABLE AS不保留用户定义的检查约束:

-- original table
CREATE TABLE foo (
  id int PRIMARY KEY NOT NULL,
  a int not null,              -- Implicit not null constraint
  b int check (b is not null), -- Explicit not null constraint
  c int check (c = 1),          -- Explicit constraint
  d INT CONSTRAINT my_check CHECK (d = 3)
);

-- clone without data(it should be stored in different schema than actual objects)
CREATE TABLE shadow_foo
AS
SELECT * 
FROM foo 
WHERE 1=2;

-- for Oracle 18c you could consider private temporary tables
CREATE PRIVATE TEMPORARY TABLE ora$shadow_foo ON COMMIT DROP DEFINITION
AS
SELECT * FROM foo WHERE 1=2;

主要查询:

SELECT c.*
FROM (SELECT * FROM all_constraints WHERE TABLE_NAME NOT LIKE 'SHADOW%') c
LEFT JOIN (SELECT * FROM all_constraints WHERE TABLE_NAME LIKE 'SHADOW%') c2
  ON c2.table_name = 'SHADOW_' || c.table_name
 AND c2.owner = c.owner
 AND c2.search_condition_vc = c.search_condition_vc
WHERE c2.owner IS NULL
  AND c.constraint_type = 'C'
  AND c.owner  LIKE 'FIDDLE%'

db<>fiddle demo

答案 2 :(得分:2)

SYS.CDEF$.TYPE#知道隐式和显式检查约束之间的区别。隐式检查约束存储为7,显式检查约束存储为1。

--Explicit constraints only.
select constraint_name, search_condition
from dba_constraints
where (owner, constraint_name) not in
    (
        --Implicit constraints.
        select dba_users.username, sys.con$.name
        from sys.cdef$
        join sys.con$
            on cdef$.con# = con$.con#
        join dba_users
            on sys.con$.owner# = dba_users.user_id
        where cdef$.type# = 7
    )
    and constraint_type = 'C'
    and table_name = 'FOO'
order by 1;


CONSTRAINT_NAME   SEARCH_CONDITION
---------------   ----------------
SYS_C00106940     b is not null
SYS_C00106941     c > 1

此解决方案具有明显的缺点,即依赖未记录的表。但这确实比依赖条件文本更准确。某些隐式检查约束不是用双引号创建的。我无法重现该问题,但发现它发生在表SYS.TAB$上。