Oracle SQL - 我可以在 DDL 的 CHECK 约束中使用子查询吗?

Posted

技术标签:

【中文标题】Oracle SQL - 我可以在 DDL 的 CHECK 约束中使用子查询吗?【英文标题】:Oracle SQL - Can I use sub-query in a CHECK constraint in DDL? 【发布时间】:2020-10-23 16:13:54 【问题描述】:

我正在使用 Oracle SQL,我想知道在创建新表时是否可以在 CHECK 约束中使用子查询。请考虑以下示例:

假设我想创建一个名为EnrollsIn 的表,它有两个属性——studentcoursestudent 是一个包含唯一学生 ID 的字符串,course 属性包含一个课程代码字符串。

CREATE TABLE EnrollsIn (
   student char(8) PRIMARY KEY,
   course char(7),
   -- Insert constraint here (Constraint is written below)
);

INSERT INTO EnrollsIn VALUE ('12345678', 'COMP200');
INSERT INTO EnrollsIn VALUE ('12345678', 'COMP300');
INSERT INTO EnrollsIn VALUE ('12345678', 'COMP400');
INSERT INTO EnrollsIn VALUE ('12345678', 'MATH100');  -- This violates the constraint written below!

现在,我希望此表有一个约束,即单个学生最多只能注册 3 门课程。换句话说,对于每个student,以下查询的值应该始终为enrollCount

-- I want the value "enrollCount" always <= 3 for all students
SELECT student, count(*) as enrollCount FROM EnrollsIn GROUP BY student;

CERATE TABLE EnrollsIn 语句中定义 CHECK 约束时,我可以使用这个子查询吗?如果是这样,我该如何定义这个约束?

【问题讨论】:

唉,你不能在检查约束中这样做。这种结构称为 SQL 断言,Oracle 或任何其他主要数据库尚不支持它,尽管已经采取措施增加支持。 实现此要求的一种方法是使用复合触发器:有关示例,请参见 this answer。或者,您可以创建一个带有检查约束的物化视图:there is an example here。 @APC:我不确定复合触发方法是否适用。如果您在两个并发会话中的每一个中为同一个学生插入两行,触发器将永远不会检测到问题,因为它只会看到每个会话中的两行,而不是所有四行,所以你肯定会得到那个学生注册了四门课程? 顺便提一下,Oracle 为字符串提供了varchar2char 用于固定长度的字符串,nobody has ever needed,使用它经常会产生错误。 @LukeWoodward - 这是一个有效的观点。为了使复合触发器工作,我们需要锁定 STUDENT 记录,该记录将过程序列化。在生产环境中并不理想,但对于家庭作业解决方案来说还可以(我一直认为这是学生入学问题的情况:D) 【参考方案1】:

最好向documentation询问:

检查约束的限制

检查约束受以下限制:

检查约束条件不能包含以下结构: 子查询和标量子查询表达式 调用用户定义的函数

【讨论】:

以上是关于Oracle SQL - 我可以在 DDL 的 CHECK 约束中使用子查询吗?的主要内容,如果未能解决你的问题,请参考以下文章

创建可重新运行的 Oracle DDL SQL 脚本

hibernate.hbm2ddl.auto + Oracle 中的自定义 sql 类型

Oracle SQL语言DDL和对象管理_超越OCP精通Oracle视频教程培训27

sql Oracle - 获取视图DDL

sql ORACLE DDL发电机

oracle ddl语句用啥编辑