如何解决哪些SQL数据库在CHECK约束中支持子查询?
| 哪些SQL数据库(如果有)支持CHECK约束中的子查询? 目前,据我所知,Oracle,MySQL和PostgreSQL还没有。 编辑 (根据初始答案进行澄清。)我正在寻找这样的东西:CREATE TABLE personnel (
...,department VARCHAR(64) NOT NULL,salary NUMERIC NOT NULL,CHECK (salary >= (SELECT MIN(p.salary) FROM payranges p WHERE p.dept = department)
AND
salary <= (SELECT MAX(p.salary) FROM payranges p WHERE p.dept = department)
)
更新
MS Access和Firebird均支持此功能。
解决方法
Access数据库引擎(ACE,Jet等)在
CHECK
约束中支持子查询,但我犹豫称它为SQL DBMS,因为它不支持入门级标准SQL-92,而MS和Access几乎没有记录AccessCHECK
约束球队。
例如,我可以证明对受影响的每一行都检查了Accessѭ1约束(SQL-92指定应在每个SQL语句之后检查它们),但这是错误还是我们不知道的功能,因为没有相关文档参考。
这是一个包含子查询的CHECK约束的非常简单的示例。它符合Full SQL-92,并且在Access中运行良好。这个想法是将表格限制为最多两行(以下SQL DDL需要ANSI-92查询模式,例如使用ADO连接,例如“ 4”):
CREATE TABLE T1
(
c INTEGER NOT NULL UNIQUE
);
ALTER TABLE T1 ADD
CONSTRAINT max_two_rows
CHECK (
NOT EXISTS (
SELECT 1
FROM T1 AS T
HAVING COUNT(*) > 2
)
);
但是,这是可以在Access中创建的另一个示例SQL-92(在Access中某些有效的ѭ1s失败,发生了严重的崩溃,需要重新启动我的机器:(但不能正常工作。这个想法是为了只允许表中恰好两行(或零行:不对空表进行约束测试):
CREATE TABLE T2
(
c INTEGER NOT NULL UNIQUE
);
ALTER TABLE T2 ADD
CONSTRAINT exactly_two_rows
CHECK (
NOT EXISTS (
SELECT 1
FROM T2 AS T
HAVING COUNT(*) <> 2
)
);
尝试在同一条语句中插入两行(假设表T1
至少有一行):
SELECT DT1.c
FROM (
SELECT DISTINCT 1 AS c
FROM T1
UNION ALL
SELECT DISTINCT 2
FROM T1
) AS DT1;
但是,这会导致ѭ1咬住。此(以及进一步的测试)意味着在将每行添加到表之后测试“ 1”,而SQL-92指定在SQL语句级别测试约束。
当您考虑到Access2010之前它没有任何触发器功能并且某些常用表否则没有真正的键时,Access具有真正的表级ѭ1约束就不足为奇了。有效状态时态表中的“已排序”键)。请注意,Access2010触发器遭受的错误/功能与在行级别(而不是语句级别)测试的错误/功能相同。
以下是VBA重现上述两种情况。复制并粘贴到任何VBA / VB6标准.bas模块(例如使用Excel)中,无需引用。在您的temp文件夹中创建一个新的.mdb,创建表,数据和测试约束是否起作用的提示(提示:设置断点,逐步执行代码,阅读注释):
Sub AccessCheckSubqueryButProblem()
On Error Resume Next
Kill Environ$(\"temp\") & \"\\DropMe.mdb\"
On Error GoTo 0
Dim cat
Set cat = CreateObject(\"ADOX.Catalog\")
With cat
.Create _
\"Provider=Microsoft.Jet.OLEDB.4.0;\" & _
\"Data Source=\" & _
Environ$(\"temp\") & \"\\DropMe.mdb\"
With .ActiveConnection
Dim Sql As String
Sql = _
\"CREATE TABLE T1 \" & vbCr & _
\"( \" & vbCr & _
\" c INTEGER NOT NULL UNIQUE \" & vbCr & _
\");\"
.Execute Sql
Sql = _
\"ALTER TABLE T1 ADD \" & vbCr & _
\" CONSTRAINT max_two_rows \" & vbCr & _
\" CHECK ( \" & vbCr & _
\" NOT EXISTS ( \" & vbCr & _
\" SELECT 1 \" & vbCr & _
\" FROM T1 AS T \" & vbCr & _
\" HAVING COUNT(*) > 2 \" & vbCr & _
\" ) \" & vbCr & _
\" );\"
.Execute Sql
Sql = _
\"INSERT INTO T1 (c) VALUES (1);\"
.Execute Sql
Sql = _
\"INSERT INTO T1 (c) VALUES (2);\"
.Execute Sql
\' The third row should (and does)
\' cause the CHECK to bite
On Error Resume Next
Sql = _
\"INSERT INTO T1 (c) VALUES (3);\"
.Execute Sql
MsgBox Err.Description
On Error GoTo 0
Sql = _
\"CREATE TABLE T2 \" & vbCr & _
\"( \" & vbCr & _
\" c INTEGER NOT NULL UNIQUE \" & vbCr & _
\");\"
.Execute Sql
Sql = _
\"ALTER TABLE T2 ADD \" & vbCr & _
\" CONSTRAINT exactly_two_rows \" & vbCr & _
\" CHECK ( \" & vbCr & _
\" NOT EXISTS ( \" & vbCr & _
\" SELECT 1 \" & vbCr & _
\" FROM T2 AS T \" & vbCr & _
\" HAVING COUNT(*) <> 2 \" & vbCr & _
\" ) \" & vbCr & _
\" );\"
.Execute Sql
\' INSERTing two rows in the same SQL statement
\' should succeed according to SQL-92
\' but fails (and we have no docs from MS
\' to indicate whether this is a bug/feature)
On Error Resume Next
Sql = _
\"INSERT INTO T2 \" & vbCr & _
\" SELECT c \" & vbCr & _
\" FROM T1;\"
.Execute Sql
MsgBox Err.Description
On Error GoTo 0
End With
Set .ActiveConnection = Nothing
End With
End Sub
, Firebird文档说,它允许在CHECK约束中进行子查询。
, SQL Server 2000+允许包含查询的UDF:您不能直接使用子查询
但是,它们在高负载下不是并发的
, H2还支持约束中的子查询。在Psql模式下:P
MariaDB似乎也不支持它作为约束。
ALTER TABLE Table_1 ADD CONSTRAINT constraint_1
CHECK (column_1 > (SELECT MAX(column_2) FROM Table_2) NOT DEFERRABLE;
重要说明:由于这本书是关于SQL-99标准的,因此该书及其他页面的内容可能并不直接适用于MariaDB。使用导航栏浏览书籍。
这种事情曾经是非法的,但是在现代的SQL变体中,
您会偶尔看到表间约束引用。
供参考,这是在MariaDB上实施检查约束的票证。截至2015年7月23日,它仍处于“打开”状态。
, 可以肯定的是,TRIGGER将在您提到的每个数据库中运行,并且您获得更多的“肘部空间”来解决您的约束。
, SQL Server支持它
您可以在以下链接中找到有价值的信息
http://www.craigsmullins.com/sql_1298.htm
他们说POSTGRESQL也支持它
http://developer.postgresql.org/pgdocs/postgres/ddl-constraints.html
DB2支持CHECK约束
http://www.ibm.com/developerworks/data/library/techarticle/dm-0401melnyk/
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。