Ms access 是ACE/Jet';运算符中的s或检查约束';破碎的';?
考虑下表中的约束,它有点愚蠢,但足够简单,可以证明我的观点。注意,为了使事情非常简单,约束的条件只涉及文字值。列Ms access 是ACE/Jet';运算符中的s或检查约束';破碎的';?,ms-access,jet,Ms Access,Jet,考虑下表中的约束,它有点愚蠢,但足够简单,可以证明我的观点。注意,为了使事情非常简单,约束的条件只涉及文字值。列ID之所以存在,是因为表必须至少有一列(!!),但该列不包含在约束中。虽然有点愚蠢(因此得名),但这是完全合法的语法,类似于将WHERE 0=1添加到SELECT查询以确保其返回零行 (标准SQL DDL代码,将在ACE/Jet的ANSI-92查询模式下执行) 以下插入操作成功: INSERT INTO Test1 (ID) VALUES (1); INSERT INTO Test3
ID
之所以存在,是因为表必须至少有一列(!!),但该列不包含在约束中。虽然有点愚蠢(因此得名),但这是完全合法的语法,类似于将WHERE 0=1
添加到SELECT
查询以确保其返回零行
(标准SQL DDL代码,将在ACE/Jet的ANSI-92查询模式下执行)
以下插入操作成功:
INSERT INTO Test1 (ID) VALUES (1);
INSERT INTO Test3 (ID) VALUES (1);
这是预期的行为。谓词5=NULL
的计算结果应为UNKNOWN
。插入
是“给予怀疑的好处”并成功。没问题
使用中的操作符考虑类似的示例:
CREATE TABLE Test2
(
ID INTEGER NOT NULL,
CONSTRAINT daft_2 CHECK (5 IN (0, 1, NULL))
);
由于约束咬合,以下插入操作失败:
INSERT INTO Test2 (ID) VALUES (1);
至少在我看来,这是出乎意料的。我希望(0,1,NULL)
中的5再次被评估为UNKNOWN
,并且INSERT
成功,原因与第一个示例相同
我希望第二个示例中的逻辑与以下第三个示例相同:
CREATE TABLE Test3
(
ID INTEGER NOT NULL,
CONSTRAINT daft_3 CHECK((5 = 0) OR (5 = 1) OR (5 = NULL))
);
以下插入操作成功:
INSERT INTO Test1 (ID) VALUES (1);
INSERT INTO Test3 (ID) VALUES (1);
这是预期的行为
我已经在SQL Server上测试了所有三个示例,所有的工作都如我所期望的那样,即所有三个INSERT
语句都成功了。事实上,检查信息模式可以发现,对于第二个示例,SQL Server as“helpfully”(grrr)重写了约束的子句,将
中的操作符替换为
((5)=NULL OR (5)=(1) OR (5)=(0))
那么,对于ACE/Jet,这里的“坏”是什么:操作符中的还是检查约束
下面是一些VBA代码,使用可为空的列来重现问题;还演示了删除约束可使插入成功:
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
子测试jetincheck()
出错时继续下一步
Kill environo$(“temp”)和“\DropMe.mdb”
错误转到0
昏猫
设置cat=CreateObject(“ADOX.Catalog”)
和猫
.创造_
“Provider=Microsoft.Jet.OLEDB.4.0;”_
“数据源=”&_
环境$(“临时”)和“\DropMe.mdb”
使用.ActiveConnection
将Sql设置为字符串
Sql=_
“创建表测试”&vbCr&_
(“&vbCr&_
“ID整数”&vbCr&_
“约束愚蠢的约束”&vbCr&_
“检查(5英寸(0,1,空))”&vbCr&_
");"
.执行Sql
Sql=“插入测试(ID)值(1);”
出错时继续下一步
.执行Sql
如果错误号为0,则
MsgBox错误说明
其他的
MsgBox“{{无错误}}”
如果结束
错误转到0
.执行“更改表测试跌落约束daft_约束”
出错时继续下一步
.执行Sql
如果错误号为0,则
MsgBox错误说明
其他的
MsgBox“{{无错误}}”
如果结束
错误转到0
以
Set.ActiveConnection=Nothing
以
端接头
编辑:我只是想试试这个:
在(1)中选择空;
--返回空值
在中选择1(空)
--返回零,即FALSE我可以通过创建验证规则来消除检查
约束(@David W.Fenton:对不起,我发现SQL DDL和ADO比DAO更容易编写,但感谢您的启发):
子测试jetinvalidationrule()
出错时继续下一步
Kill environo$(“temp”)和“\DropMe.mdb”
错误转到0
昏猫
设置cat=CreateObject(“ADOX.Catalog”)
和猫
.创造_
“Provider=Microsoft.Jet.OLEDB.4.0;”_
“数据源=”&_
环境$(“临时”)和“\DropMe.mdb”
使用.ActiveConnection
将Sql设置为字符串
Sql=_
“创建表测试”&vbCr&_
(“&vbCr&_
“ID整数”&vbCr&_
");"
.执行Sql
以
'创建验证规则
丁正
Set jeng=CreateObject(“JRO.JetEngine”)
jeng.RefreshCache.ActiveConnection
.表格(“测试”).列(“ID”)_
.Properties(“Jet OLEDB:列验证规则”)。值=_
5英寸(0,1,空)
jeng.RefreshCache.ActiveConnection
使用.ActiveConnection
Sql=“插入测试(ID)值(1);”
出错时继续下一步
.执行Sql
如果错误号为0,则
MsgBox错误说明
其他的
MsgBox“{{无错误}}”
如果结束
错误转到0
以
Set.ActiveConnection=Nothing
以
端接头
验证规则被咬住并插入失败。因此,我怀疑IN子句的行为出人意料。将来我将使用嵌套或子句 我可以通过创建一个验证规则来消除检查
约束(@David W.Fenton:对不起,我发现SQL DDL和ADO比DAO更容易编写,但感谢您的启发):
子测试jetinvalidationrule()
出错时继续下一步
Kill environo$(“temp”)和“\DropMe.mdb”
错误转到0
昏猫
设置cat=CreateObject(“ADOX.Catalog”)
和猫
.创造_
“Provider=Microsoft.Jet.OLEDB.4.0;”_
“数据源=”&_
环境$(“临时”)和“\DropMe.mdb”
使用.ActiveConnection
将Sql设置为字符串
Sql=_
“创建表测试”&vbCr&_
(“&vbCr&_
“ID整数”&vbCr&_
");"
.执行Sql
以
'创建验证规则
丁正
Set jeng=CreateObject(“JRO.JetEngine”)
jeng.RefreshCache.ActiveConnection
.表格(“测试”).列(“ID”)_
.Properties(“Jet OLEDB:列验证规则”)。值=_
5英寸(0,1,空)
jeng.RefreshCache.ActiveConnection
使用.ActiveConnection
Sql=“插入到T中”