2009-06-04 26 views
1

考虑下面的表格,它的约束有点笨拙,但足以证明我的观点。请注意,为了使事情变得非常简单,约束条件只涉及文字值。列ID仅存在,因为表必须至少有一列(!!),但该列未包含在约束中。虽然有点愚蠢(因此名称),这是完全合法的语法,类似于将WHERE 0 = 1添加到SELECT查询以确保它返回零行。ACE/Jet的IN运算符或CHECK约束是否“损坏”?

(标准SQL DDL代码,将在ACE/Jet的ANSI-92查询模式执行)

CREATE TABLE Test1 
(
    ID INTEGER NOT NULL, 
    CONSTRAINT daft_1 CHECK (5 = NULL) 
); 

以下INSERT成功:

INSERT INTO Test1 (ID) VALUES (1); 

这是正常现象。谓词5 = NULL应评估为UNKNOWNINSERT是'给予怀疑的好处'并且成功。那里没问题。

使用IN运营商考虑这个类似的例子:

CREATE TABLE Test2 
(
    ID INTEGER NOT NULL, 
    CONSTRAINT daft_2 CHECK (5 IN (0, 1, NULL)) 
); 

以下INSERT因为约束咬伤失败:

INSERT INTO Test2 (ID) VALUES (1); 

这是出乎意料的behviour,通过我至少。我希望5 IN (0, 1, NULL)再次被评估为UNKNOWNINSERT成功的原因与第一个例子相同。

我期望在第二示例中的逻辑是相同的如下面的第三示例:

CREATE TABLE Test3 
(
    ID INTEGER NOT NULL, 
    CONSTRAINT daft_3 CHECK((5 = 0) OR (5 = 1) OR (5 = NULL)) 
); 

以下INSERT成功:

INSERT INTO Test3 (ID) VALUES (1); 

这是预期行为。

我已经测试了SQL Server上的所有三个示例,并且所有工作都如我所料,即所有三个INSERT语句都成功。事实上,检查信息模式显示,在第二个例子中的SQL Server作为“有益”(哎呀)改写约束的条款与

((5)=NULL OR (5)=(1) OR (5)=(0)) 

所以更换IN运营商,为ACE /喷气,什么是“破'这里:IN运营商或CHECK约束?

下面是一些使用NULLable列重现问题的VBA代码;也证明了下降的约束使得INSERT成功:

Sub TestJetInCheck() 

    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 Test" & vbCr & _ 
      "(" & vbCr & _ 
      " ID INTEGER, " & vbCr & _ 
      " CONSTRAINT daft_constraint " & vbCr & _ 
      "  CHECK (5 IN (0, 1, NULL))" & vbCr & _ 
      ");" 
     .Execute Sql 

     Sql = "INSERT INTO Test (ID) VALUES (1);" 

     On Error Resume Next 
     .Execute Sql 
     If Err.Number <> 0 Then 
     MsgBox Err.Description 
     Else 
     MsgBox "{{no error}}" 
     End If 
     On Error GoTo 0 

     .Execute "ALTER TABLE Test DROP CONSTRAINT daft_constraint;" 

     On Error Resume Next 
     .Execute Sql 
     If Err.Number <> 0 Then 
     MsgBox Err.Description 
     Else 
     MsgBox "{{no error}}" 
     End If 
     On Error GoTo 0 

    End With 

    Set .ActiveConnection = Nothing 
    End With 
End Sub 

编辑:我只是想试试这个:

SELECT NULL(1); - 返回NULL

SELECT 1 IN(NULL) - 返回零即FALSE

+0

为什么不尝试使用DAO而不是DDL? – 2009-06-06 04:21:51

回答

0

我可以通过创建专门消除CHECK约束验证规则(@大卫W.芬顿:对不起,我发现SQL DDL和ADO,更容易比DAO编写但感谢灵感):

Sub TestJetInValidationRule() 

    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 Test" & vbCr & _ 
      "(" & vbCr & _ 
      " ID INTEGER" & vbCr & _ 
      ");" 
     .Execute Sql 
    End With 

    ' Create Validation Rules 
    Dim jeng 
    Set jeng = CreateObject("JRO.JetEngine") 
    jeng.RefreshCache .ActiveConnection 

    .Tables("Test").Columns("ID") _ 
    .Properties("Jet OLEDB:Column Validation Rule").value = _ 
    "5 IN (0, 1, NULL)" 

    jeng.RefreshCache .ActiveConnection 

    With .ActiveConnection 

     Sql = "INSERT INTO Test (ID) VALUES (1);" 

     On Error Resume Next 
     .Execute Sql 
     If Err.Number <> 0 Then 
     MsgBox Err.Description 
     Else 
     MsgBox "{{no error}}" 
     End If 
     On Error GoTo 0 

    End With 

    Set .ActiveConnection = Nothing 
    End With 
End Sub 

验证规则咬合和INSERT失败。因此,我怀疑IN子句意外行为。我将在未来使用嵌套OR子句!