Рассмотрим следующую таблицу с ограничением, которое немного глупо, но достаточно просто, чтобы продемонстрировать мою точку зрения. Обратите внимание, что для простоты критерии ограничения включают только буквальные значения. Столбец ID
существует только потому, что в таблице должен быть хотя бы один столбец (!!), но этот столбец не включен в ограничение. Несмотря на небольшую глупость (отсюда и название), это вполне допустимый синтаксис и похож на добавление WHERE 0 = 1
к запросу SELECT
, чтобы гарантировать, что он возвращает ноль строк.
(стандартный код DDL SQL, будет выполняться в режиме запросов 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
должен быть оценен до UNKNOWN
. INSERT
«получает выгоду от сомнения» и добивается успеха. Там нет проблем.
Рассмотрим аналогичный пример, используя оператор IN
:
CREATE TABLE Test2
(
ID INTEGER NOT NULL,
CONSTRAINT daft_2 CHECK (5 IN (0, 1, NULL))
);
Следующее INSERT
завершается ошибкой из-за укусов ограничения:
INSERT INTO Test2 (ID) VALUES (1);
Это неожиданно, по крайней мере для меня. Я ожидаю, что 5 IN (0, 1, NULL)
снова будет оцениваться как UNKNOWN
, а INSERT
будет успешным по тем же причинам, что и в первом примере.
Я ожидаю, что логика во втором примере будет такой же, как в следующем третьем примере:
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 как «услужливо» (grrr) переписать условие ограничения, чтобы заменить оператор IN
на
((5)=NULL OR (5)=(1) OR (5)=(0))
Итак, что для ACE / Jet, что здесь «сломано»: оператор IN
или ограничение CHECK
?
Вот некоторый код VBA для воспроизведения проблемы с использованием столбца NULLable; также демонстрирует, что удаление ограничения позволяет 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
РЕДАКТИРОВАТЬ: Я просто подумал попробовать это:
ВЫБЕРИТЕ NULL IN (1);
- возвращает NULL
ВЫБЕРИТЕ 1 IN (NULL)
- возвращает ноль, т.е. FALSE