Какие базы данных SQL поддерживают подзапросы в ограничениях CHECK?
Какие базы данных SQL, если таковые имеются, поддерживают подзапросы в ограничениях CHECK?
В настоящее время, насколько мне известно, Oracle, MySQL и PostgreSQL этого не делают.EDIT
(уточнение, основанное на первоначальных ответах.) Я ищу что-то вроде этого:
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 поддерживают эту функцию.
6 ответов:
Движок баз данных Access (ACE, Jet, что угодно) поддерживает подзапросы в ограничениях
CHECK
, но я не решаюсь назвать его СУБД SQL, потому что он не поддерживает стандарт начального уровня SQL-92, а ограничения доступаCHECK
едва документированы MS и командой Access.Например, я могу продемонстрировать, что ограничения доступа
CHECK
проверяются для каждой затронутой строки (SQL-92 указывает, что они должны проверяться после каждой инструкции SQL), но является ли это ошибкой или особенностью мы не знаем, потому что нет никакой документации, на которую можно было бы сослаться.
Вот очень простой пример ограничения CHECK, содержащего подзапрос. Он совместим с полным 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
s сбой доступа с ужасным сбоем, который требует перезапуска моей машины: (но не работает должным образом. Идея состоит в том, чтобы разрешить только две строки в таблице (или нулевые строки: ограничения не проверяются для пустой таблицы):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.Не должно быть слишком большим сюрпризом, что Access имеет действительно табличные ограничения
CHECK
, если учесть, что до Access2010 он не имел никакой функциональности триггера и некоторые часто используемые таблицы в противном случае не имели бы истинного ключа (например, "секвенированный" ключ в временной таблице допустимого состояния). Обратите внимание, что триггеры Access2010 страдают от той же ошибки/функции, что и тестируемые на уровне строк, а не на уровне высказываний.Ниже приводится VBA для воспроизведения двух сценариев, описанных выше. Скопируйте и вставьте в любой стандарт VBA/VB6 .модуль bas (например, используйте Excel), ссылки не требуются. Создает новое .mdb в папке temp создает таблицы, данные и тесты, которые работают/не работают с ограничениями (подсказка: установите точку останова, выполните шаг по коду, прочтите комментарии):
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 + разрешает UDFs, содержащие запросы: вы не можете использовать подзапросы напрямую
Однако они не являются параллельными при высоких нагрузках
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-07-23, он все еще находится в" открытом " состоянии.
Вполне уверен, что триггер будет работать в каждой из упомянутых вами баз данных, и вы получите гораздо больше "локтевого пространства" для разработки вашего ограничения.
SQL server поддерживает его Вы можете найти ценную информацию по следующей ссылке
Http://www.craigsmullins.com/sql_1298.htm
Они говорят, что POSTGRESQL также поддерживает его
Http://developer.postgresql.org/pgdocs/postgres/ddl-constraints.html
DB2 поддерживает ограничение проверки
Http://www.ibm.com/developerworks/data/library/techarticle/dm-0401melnyk/