微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

哪些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)
)

UPDATE

MS Access和Firebird都支持功能.

解决方法

Access数据库引擎(ACE,Jet,等等)支持CHECK约束中的子查询,但我不愿称它为sql DBMS,因为它不支持入门级标准sql-92和MS和Access团队几乎没有记录Access CHECK约束.

例如,我可以证明对每个受影响的行检查Access CHECK约束(sql-92指定在每个sql语句之后应该检查它们)但是这是一个bug还是我们不知道的功能,因为没有文档到参考.

这是一个包含子查询的CHECK约束的一个非常简单的例子.它符合Full sql-92,在Access中运行良好.我们的想法是将表限制为最多两行(以下sql DDL需要ANSI-92 Query Mode,例如使用ADO连接,例如Access.CurrentProject.Connection):

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

但是,这是另一个例子,即sql-92,可以在Access中创建(一些有效的CHECK在Access中失败,需要重新启动我的机器的可怕崩溃:(但是无法正常运行.这个想法只是为了允许表中恰好有两行(或零行:不测试空表的约束):

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;

但是,这导致CHECK咬人.这(以及进一步测试)意味着在每行添加到表之后测试CHECK,而sql-92指定在sql语句级别测试约束.

当您考虑到Access2010之前它没有任何触发功能并且某些经常使用的表没有真正的密钥(例如”时,Access确实具有表级CHECK约束,这不应该太令人意外.在有效状态时态表中对密钥进行排序.请注意,Access2010触发器遇到与在行级别而不是在语句级别测试它们相同的错误/功能.

以下是VBA重现上述两种情况.复制并粘贴到任何VBA / VB6标准.bas模块(例如使用Excel),不需要引用.在临时文件夹中创建一个新的.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

原文地址:https://www.jb51.cc/mssql/77454.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐