Перевірка обмеження в MySQL не працює


126

Спочатку я створив таблицю на кшталт

CREATE TABLE Customer (
  SD integer CHECK (SD > 0),
  Last_Name varchar (30),
  First_Name varchar(30)
);

а потім вставили значення в цю таблицю

INSERT INTO Customer values ('-2','abc','zz');

MySQL не показує помилку, він прийняв значення.


Частково згоден. З огляду на те, що ви намагалися ним скористатися, можна припустити, що ви задавали обидва питання. Насправді відповідь, яку ви прийняли, головним чином пояснює, чому вона не працює.
igorrs

1
Ви можете проголосувати за цей запит на функцію: bugs.mysql.com/bug.php?id=3464, але він не звертав уваги протягом десятиліття.
Джаред Бек

11
Ви можете використовувати обмеження CHECK в MariaDB з версії 10.2.1 .
joanq

Відповіді:


140

MySQL 8.0.16 - перша версія, яка підтримує обмеження CHECK.

Читайте https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html

Якщо ви використовуєте MySQL 8.0.15 або новішої версії, у довідковому посібнику MySQL написано:

Цей CHECKпункт проаналізований, але всі ігрові системи зберігання ігнорують.

Спробуйте спусковий гачок ...

mysql> delimiter //
mysql> CREATE TRIGGER trig_sd_check BEFORE INSERT ON Customer 
    -> FOR EACH ROW 
    -> BEGIN 
    -> IF NEW.SD<0 THEN 
    -> SET NEW.SD=0; 
    -> END IF; 
    -> END
    -> //
mysql> delimiter ;

Сподіваюся, що це допомагає.


9
Тут ви знайдете як викликати помилку замість: stackoverflow.com/a/7189396/1144966
petermeissner

41
Це одне з величезних іскрометних райдужних причин того, що я завжди буду використовувати PostgreSQL замість MySQL, тому що я маю вибір.
Reinderien

5
Цікаво, чи було б 10-хвилинною або 15-хвилинною розробкою в MySQL надіслати попередження, якщо аналізатор стикається з CHECKвизначеним обмеженням. А-а-а, це було б занадто прямо ...
gaborsch

75

На жаль, MySQL не підтримує обмеження перевірки SQL. Ви можете визначити їх у своєму запиті DDL з міркувань сумісності, але вони просто ігноруються.

Існує проста альтернатива

Ви можете створювати BEFORE INSERTта BEFORE UPDATEтригери, які або спричиняють помилку, або встановлюють для поля значення за замовчуванням, коли вимоги даних не виконані.

Приклад BEFORE INSERTроботи після MySQL 5.5

DELIMITER $$
CREATE TRIGGER `test_before_insert` BEFORE INSERT ON `Test`
FOR EACH ROW
BEGIN
    IF CHAR_LENGTH( NEW.ID ) < 4 THEN
        SIGNAL SQLSTATE '12345'
            SET MESSAGE_TEXT := 'check constraint on Test.ID failed';
    END IF;
END$$   
DELIMITER ;  

Перед MySQL 5.5 вам довелося викликати помилку, наприклад, викликати не визначену процедуру.

В обох випадках це спричиняє неявний відкат транзакцій. MySQL не дозволяє сам оператор ROLLBACK в рамках процедур і тригерів.

Якщо ви не хочете відмовляти транзакцію (INSERT / UPDATE має пройти навіть при невдалому "обмеженні перевірки", ви можете перезаписати значення, використовуючи SET NEW.ID = NULLяке встановить ідентифікатор у значення поля за замовчуванням, насправді не має сенсу для ідентифікатора тхо

Редагувати: Вилучена цитата.

Щодо :=оператора:

На відміну від цього =, :=оператор ніколи не трактується як оператор порівняння. Це означає, що ви можете використовувати :=в будь-якому дійсному операторі SQL (не тільки в операторах SET), щоб призначити значення змінній.

https://dev.mysql.com/doc/refman/5.6/uk/assignment-operators.html

Що стосується котирування ідентифікатора backtick:

Символом котирування ідентифікатора є зворотний вибір ("` ")

Якщо ввімкнено режим SSI ANSI_QUOTES, також можна допустити котирування ідентифікаторів у подвійних лапках

http://dev.mysql.com/doc/refman/5.6/uk/identifiers.html


7
... не дуже простий, принаймні у порівнянні з CHECK :(. Coupla tutes: net.tutsplus.com/tutorials/databases/… , sitepoint.com/how-to-create-mysql-triggers
Бен

Фу, це виглядає дуже об'ємно. Я думаю, що краще створити кортеж у python і перевірити значення там, а не ставити це.
OzzyTheGiant

Швидке запитання: чому це не працює без встановлення DELIMITER?
ddz

52

CHECK обмеження ігноруються MySQL, як пояснено в коментарі, який є дрібним у документах: CREATE TABLE

Цей CHECKпункт проаналізований, але всі ігрові системи зберігання ігнорують.


2
@thefiloe: Правильно, в інших СУБД з коректною реалізацією CHECKобмежень, якщо CHECKоцінювання для FALSEвставки (або оновлення) не робиться і викликана помилка.
ypercubeᵀᴹ

Виправлено у MariaDB (див. Цю відповідь stackoverflow.com/a/44333349 ).
Jérôme

@ Jérôme Я знаю, у мене є кілька (останніх) відповідей, які включають вдосконалення в цій галузі (були інші способи вирішити цю проблему, як в MariaDB, так і в MySQL, перш ніж MariaDB належним чином застосував обмеження CHECK). У чому я не впевнений, чи варто мені відредагувати всі свої старі відповіді!
ypercubeᵀᴹ

Я вважаю, що мій коментар із посиланням на більш пізню відповідь чудовий. Або краще, ніж нічого. Можливо, я мав би відредагувати. Я не хотів тиснути на тебе, щоб щось зробити.
Jérôme



1

Перевірки обмежень підтримуються з версії 8.0.15 (ще не буде випущено)

https://bugs.mysql.com/bug.php?id=3464

[23 січня 16:24] Пол Дюбуа

Опублікував розробник: Виправлено в 8.0.15.

Раніше MySQL дозволяв обмежену форму синтаксису обмежень CHECK, але аналізував та ігнорував її. Тепер MySQL реалізує основні функції обмежень для перевірки таблиці та стовпців для всіх механізмів зберігання даних. Обмеження визначаються за допомогою операторів CREATE TABLE та ALTER TABLE.


1

Оновіть до MySQL 8.0.16, щоб використовувати checks:

Станом на MySQL 8.0.16, CREATE TABLE дозволяє виконувати основні функції обмежень для перевірки таблиці та стовпців для всіх механізмів зберігання даних. CREATE TABLE дозволяє наступний синтаксис CHECK обмежень для обмежень таблиці та обмежень стовпців.

MySQL перевіряє документацію


-2

спробуйте set sql_mode = 'STRICT_TRANS_TABLES'АБОSET sql_mode='STRICT_ALL_TABLES'


2
цей actuall не допомагає (MySQL 5.6), він перешкоджає введенню даних помилкового типу, але не вводить дані, які не відповідають CHECKобмеженню
petermeissner
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.