MySQL'de CHECK kısıtlaması çalışmıyor


126

İlk önce şöyle bir tablo oluşturdum

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

ve sonra bu tabloya değerler ekledi

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

MySQL bir hata göstermiyor, değerleri kabul etti.


Kısmen katılıyorum. Kullanmaya çalıştığınız göz önüne alındığında, her iki soruyu da sorduğunuz varsayılabilir. Aslında, kabul ettiğiniz cevap esas olarak neden işe yaramadığını açıklamaktır.
igorrs

1
Bu özellik isteğine oy verebilirsiniz: bugs.mysql.com/bug.php?id=3464, ancak on yıldır hiç ilgi görmedi.
Jared Beck

11
10.2.1 sürümünden itibaren MariaDB'de CHECK kısıtlamalarını kullanabilirsiniz .
joanq

Yanıtlar:


140

MySQL 8.0.16 , CHECK kısıtlamalarını destekleyen ilk sürümdür.

Https://dev.mysql.com/doc/refman/8.0/en/create-table-check-constraints.html okuyun

MySQL 8.0.15 veya önceki bir sürümünü kullanıyorsanız, MySQL Referans Kılavuzu şunu söyler:

CHECKHükmü tüm depolama motorları tarafından çözümlenen fakat göz ardı edilir.

Bir tetikleyici deneyin ...

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 ;

Umarım yardımcı olur.


9
Burada bunun yerine bir hatayı nasıl tetikleyeceğinizi bulacaksınız: stackoverflow.com/a/7189396/1144966
petermeissner

41
Bu, her ne olursa olsun MySQL yerine PostgreSQL kullanmamın parlak ve ışıltılı gökkuşağı nedenlerinden biridir.
Reinderien

5
Acaba MySQL'de, ayrıştırıcı CHECKtanımlanmış bir kısıtla karşılaşırsa bir uyarı atmanın 10 dakikalık mı yoksa 15 dakikalık bir geliştirme mi olacağını merak ediyorum . Ahhh, bu çok basit olur ...
gaborsch

75

Maalesef MySQL, SQL kontrol kısıtlamalarını desteklemez. Uyumluluk nedeniyle bunları DDL sorgunuzda tanımlayabilirsiniz, ancak bunlar yok sayılır.

Basit bir alternatif var

Veri gereksinimleri karşılanmadığında bir hataya neden olan veya alanı varsayılan değerine ayarlayan oluşturabilir BEFORE INSERTve BEFORE UPDATEtetikleyebilirsiniz.

BEFORE INSERTMySQL 5.5'ten sonra çalışma örneği

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'ten önce, bir hataya neden olmanız gerekiyordu, örneğin tanımsız bir prosedürü çağırmak.

Her iki durumda da bu, örtük bir işlem geri dönüşüne neden olur. MySQL, prosedürler ve tetikleyiciler içinde ROLLBACK ifadesinin kendisine izin vermez.

İşlemi geri almak istemiyorsanız (INSERT / UPDATE, başarısız bir "kontrol kısıtlaması" olsa bile geçmelidir. Kullanarak SET NEW.ID = NULL, kimliği alanların varsayılan değerine ayarlayacak olan değerin üzerine yazabilirsiniz, bir id için gerçekten mantıklı değildir tho

Düzenleme: Başıboş alıntı kaldırıldı.

Hakkında :=operatörü:

Aksine =, :=operatör hiçbir zaman bir karşılaştırma operatörü olarak yorumlanmaz. Bu :=, bir değişkene bir değer atamak için herhangi bir geçerli SQL ifadesinde (yalnızca SET ifadelerinde değil) kullanabileceğiniz anlamına gelir .

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

Backtick tanımlayıcı alıntılarıyla ilgili olarak:

Tanımlayıcı tırnak karakteri geri işarettir ("" ")

ANSI_QUOTES SQL modu etkinleştirilirse, tanımlayıcıların çift tırnak işareti içinde alınmasına da izin verilir

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


7
... çok basit değil, :( CHECK'e için coupla Hristiyanlık kıyasla en azından. net.tutsplus.com/tutorials/databases/... , sitepoint.com/how-to-create-mysql-triggers
Ben

ugh bu çok hantal görünüyor. Sanırım
python'da

Hızlı soru: Bu, neden DELIMITER?
ddz

52

CHECK Belgelerdeki küçük bir yorumda açıklandığı gibi kısıtlamalar MySQL tarafından yok sayılır: CREATE TABLE

CHECKHükmü tüm depolama motorları tarafından çözümlenen fakat göz ardı edilir.


2
@thefiloe: Doğru, doğru uygulama ile diğer DBMS CHECKkısıtlamaları, eğer CHECKdeğerlendirir için FALSEdaha sonra ek (veya güncelleştirme) yapmadı ve bir hata meydana gelir.
ypercubeᵀᴹ

MariaDB'de düzeltildi (bu cevaba bakın stackoverflow.com/a/44333349 ).
Jérôme

@ Jérôme Biliyorum, bu alandaki iyileştirmeleri içeren bazı (daha yeni) yanıtlarım var (MariaDB, CHECK kısıtlamalarını düzgün bir şekilde uygulamadan önce hem MariaDB'de hem de MySQL'de bu sorunu çözmek için başka yollar vardı). Emin olmadığım şey, gidip tüm eski yanıtlarımı düzenlemeli miyim?
ypercubeᵀᴹ

Sanırım daha yeni bir cevaba bağlantı içeren yorumum yeterli. Ya da hiç yoktan iyidir. Belki de düzenlemeliydim. Sana bir şey yapman için baskı yapmak istemedim.
Jérôme



1

Kontrol kısıtlamaları 8.0.15 sürümünden itibaren desteklenmektedir (henüz yayınlanmamıştır)

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

[23 Ocak 16:24] Paul Dubois

Geliştirici tarafından gönderildi: 8.0.15'te düzeltildi.

Önceden, MySQL sınırlı bir CHECK kısıtlama sözdizimi biçimine izin veriyordu, ancak ayrıştırıp yok sayıyordu. MySQL artık tüm depolama motorları için tablo ve sütun KONTROL kısıtlamalarının temel özelliklerini uygulamaktadır. Kısıtlamalar, CREATE TABLE ve ALTER TABLE ifadeleri kullanılarak tanımlanır.


1

MySQL 8.0.16 sürümüne güncelleyin checks:

MySQL 8.0.16'dan itibaren, CREATE TABLE, tüm depolama motorları için tablo ve sütun KONTROL kısıtlamalarının temel özelliklerine izin verir. CREATE TABLE, hem tablo kısıtlamaları hem de sütun kısıtlamaları için aşağıdaki CHECK kısıtlama sözdizimine izin verir

MySQL Checks Belgeleri


-2

set sql_mode = 'STRICT_TRANS_TABLES'OR ile deneSET sql_mode='STRICT_ALL_TABLES'


2
bu actuall yardımcı olmuyor (MySQL 5.6) yanlış türde veri girmeyi engelliyor ancak CHECKkısıtlamaya uymayan verilerin girilmesini
engelliyor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.