在 Oracle ALL_CONSTRAINTS 中仅查找用户定义的检查约束
Find only user-defined check constraints in Oracle ALL_CONSTRAINTS
考虑这个 table 定义:
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 语句中定义的约束。这些约束可能会或可能不会被命名。在上面的示例中,它们没有命名。我怎样才能只发现 "explicit" 检查约束,而忽略隐式约束?
例如当我查询 ALL_CONSTRAINTS
:
SELECT *
FROM all_constraints
WHERE constraint_type = 'C'
AND table_name = 'FOO';
我看不出有什么方法可以区分 explicitness/implicitness:
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
我当然可以对某人使用确切 "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
我把这个作为答案放在这里,因为这对某些人来说可能已经足够好了,但我真的想要一个更可靠的解决方案。
想法:您可以将 table 与其对应的 "shadow" 进行比较。 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%'
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
此解决方案的明显缺点是依赖未记录的 tables。但它似乎确实比依赖条件文本更准确。一些隐式检查约束是 not 用双引号创建的。我无法重现该问题,但我发现它发生在 table SYS.TAB$
.
考虑这个 table 定义:
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 语句中定义的约束。这些约束可能会或可能不会被命名。在上面的示例中,它们没有命名。我怎样才能只发现 "explicit" 检查约束,而忽略隐式约束?
例如当我查询 ALL_CONSTRAINTS
:
SELECT *
FROM all_constraints
WHERE constraint_type = 'C'
AND table_name = 'FOO';
我看不出有什么方法可以区分 explicitness/implicitness:
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
我当然可以对某人使用确切 "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
我把这个作为答案放在这里,因为这对某些人来说可能已经足够好了,但我真的想要一个更可靠的解决方案。
想法:您可以将 table 与其对应的 "shadow" 进行比较。 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%'
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
此解决方案的明显缺点是依赖未记录的 tables。但它似乎确实比依赖条件文本更准确。一些隐式检查约束是 not 用双引号创建的。我无法重现该问题,但我发现它发生在 table SYS.TAB$
.