MySQL의 CHECK 제약 조건이 작동하지 않습니다


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 그러나 10 년 동안 아무런 관심도받지 못했습니다.
Jared Beck

11
버전 10.2.1의 MariaDB에서 CHECK 제약 조건을 사용할 수 있습니다 .
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
이것은 선택의 여지가있는 MySQL 대신 항상 PostgreSQL을 사용하는 광대 한 이유 중 하나입니다.
Reinderien

5
파서에 CHECK정의 된 제약 조건이 발생하면 경고를 발생시키는 것이 MySQL에서 10 분 또는 15 분의 개발 일지 궁금합니다 . 아아, 그것은 너무 간단합니다 ...
gaborsch

75

불행히도 MySQL은 SQL 검사 제약 조건을 지원하지 않습니다. 호환성을 위해 DDL 쿼리에서 정의 할 수 있지만 무시됩니다.

간단한 대안이 있습니다

데이터 요구 사항이 충족되지 않으면 오류를 발생 시키거나 필드를 기본값으로 설정하는 트리거를 생성 BEFORE INSERT하고 BEFORE UPDATE트리거 할 수 있습니다.

BEFORE INSERTMySQL 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가 실패한 "check constraint"로도 통과해야 SET NEW.ID = NULL합니다. id를 필드 기본값으로 설정하는 값을 덮어 쓸 수 있습니다 . id에 대해서는 실제로 의미가 없습니다. 그래도

편집 : 길 잃은 따옴표를 제거했습니다.

:=운영자에 관하여 :

달리 =:=연산자는 비교 연산자로 해석되지 않습니다. 이는 :=변수에 값을 할당하기 위해 SET 문뿐만 아니라 모든 유효한 SQL 문에서 사용할 수 있음을 의미합니다 .

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

백틱 식별자 인용에 대해 :

식별자 인용 문자는 백틱 ( "`")입니다.

ANSI_QUOTES SQL 모드가 사용 가능한 경우 큰 따옴표 안에 식별자를 인용 할 수도 있습니다.

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


7
... 아주 간단하지, :( CHECK에 Coupla의에서 결정한 비해 적어도 :. net.tutsplus.com/tutorials/databases/... , sitepoint.com/how-to-create-mysql-triggers

이건 매우 부피가 커 보인다. 나는 오히려 파이썬에서 튜플을 만들고 이것을 넣는 대신 값을 확인한다고 생각합니다.
OzzyTheGiant

빠른 질문 : 왜 이것이 설정하지 않으면 작동하지 DELIMITER않습니까?
ddz

52

CHECK 문서의 작은 설명에 설명 된 것처럼 MySQL에서는 제약 조건이 무시됩니다. CREATE TABLE

CHECK절은 구문 분석되었지만 모든 스토리지 엔진에서 무시됩니다.


2
@thefiloe : 올바른 CHECK제약 조건 구현을 가진 다른 DBMS 에서 CHECK평가 FALSE하면 삽입 (또는 업데이트)이 수행되지 않고 오류가 발생합니다.
ypercubeᵀᴹ

MariaDB에서 수정되었습니다 (이 답변 stackoverflow.com/a/44333349 참조 ).
Jérôme

@ Jérôme 나는이 분야의 개선 사항을 포함하는 (최근의) 답변을 가지고 있습니다 (MariaDB와 CHECK 제약 조건을 올바르게 구현하기 전에 MariaDB와 MySQL 모두 에서이 문제를 해결할 다른 방법이있었습니다). 확실하지 않은 것은 이전 답변을 모두 편집 해야하는지 여부입니다!
ypercubeᵀᴹ

더 최근 답변에 대한 링크가있는 내 의견이 좋다고 생각합니다. 아니면 아무것도 아닌 것보다 낫습니다. 아마도 편집했을 것입니다. 난 당신에게 아무것도 압력을 가하려하지 않았습니다.
Jérôme



1

점검 제한 조건은 버전 8.0.15부터 지원됩니다 (아직 릴리스)

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

[1 월 23 일 16:24] Paul Dubois

개발자가 게시 : 8.0.15에서 수정되었습니다.

이전에는 MySQL이 제한된 형식의 CHECK 제약 조건 구문을 허용했지만 구문 분석하고 무시했습니다. MySQL은 이제 모든 스토리지 엔진에 대해 테이블 ​​및 열 CHECK 제약 조건의 핵심 기능을 구현합니다. 제약 조건은 CREATE TABLE 및 ALTER TABLE 문을 사용하여 정의됩니다.


1

다음을 사용하려면 MySQL 8.0.16으로 업데이트하십시오 checks.

MySQL 8.0.16부터 CREATE TABLE은 모든 스토리지 엔진에 대해 테이블 ​​및 열 CHECK 제약 조건의 핵심 기능을 허용합니다. CREATE TABLE은 테이블 제약 조건과 열 제약 조건 모두에 대해 다음과 같은 CHECK 제약 조건 구문을 허용합니다.

MySQL 점검 문서


-2

set sql_mode = 'STRICT_TRANS_TABLES'OR로 시도하십시오SET sql_mode='STRICT_ALL_TABLES'


2
실제로는 도움이되지 않습니다 (MySQL 5.6) 그것은 거짓 유형의 데이터를 입력하지 CHECK
못하지만
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.