PERIKSA kendala di MySQL tidak berfungsi

126

Pertama saya membuat tabel seperti

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

dan kemudian memasukkan nilai dalam tabel itu

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

MySQL tidak menunjukkan kesalahan, ia menerima nilai.

JohnRaja
sumber
Setuju sebagian. Mengingat Anda mencoba menggunakannya, dapat diasumsikan bahwa Anda mengajukan kedua pertanyaan. Sebenarnya, jawaban yang Anda terima terutama menjelaskan mengapa itu tidak berhasil.
igorrs
1
Anda dapat memberikan suara pada permintaan fitur ini: bugs.mysql.com/bug.php?id=3464 tetapi belum menerima perhatian dalam satu dekade.
Jared Beck
11
Anda dapat menggunakan PERIKSA kendala di MariaDB dari versi 10.2.1 .
joanq

Jawaban:

140

MySQL 8.0.16 adalah versi pertama yang mendukung kendala CHECK.

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

Jika Anda menggunakan MySQL 8.0.15 atau lebih lama, Manual Referensi MySQL mengatakan:

The CHECKklausul parsing tapi diabaikan oleh semua mesin penyimpanan.

Coba pemicu ...

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 ;

Semoga itu bisa membantu.

David Kerins
sumber
9
Di sini Anda akan menemukan cara memicu kesalahan sebagai gantinya: stackoverflow.com/a/7189396/1144966
petermeissner
41
Ini adalah salah satu dari banyak pelangi gemerlap alasan bahwa saya akan selalu menggunakan PostgreSQL bukan MySQL yang diberikan pilihan apa pun.
Reinderien
5
Saya bertanya-tanya apakah akan 10 menit atau 15 menit pengembangan di MySQL untuk memberikan peringatan jika parser menemukan CHECKkendala yang ditentukan. Ahhh, itu terlalu mudah ...
gaborsch
75

Sayangnya MySQL tidak mendukung kendala pemeriksaan SQL. Anda bisa mendefinisikannya dalam permintaan DDL Anda untuk alasan kompatibilitas tetapi mereka hanya diabaikan.

Ada alternatif sederhana

Anda bisa membuat BEFORE INSERTdan BEFORE UPDATEmemicu yang menyebabkan kesalahan atau mengatur bidang ke nilai default ketika persyaratan data tidak terpenuhi.

Contoh untuk BEFORE INSERTbekerja setelah 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 ;  

Sebelum ke MySQL 5.5 Anda harus menyebabkan kesalahan, misalnya memanggil prosedur yang tidak ditentukan.

Dalam kedua kasus ini menyebabkan kemunduran transaksi implisit. MySQL tidak mengizinkan pernyataan ROLLBACK itu sendiri di dalam prosedur dan pemicu.

Jika Anda tidak ingin mengembalikan transaksi (INSERT / UPDATE harus lulus bahkan dengan "periksa kendala" gagal Anda dapat menimpa nilai menggunakan SET NEW.ID = NULLyang akan mengatur id ke nilai default bidang, tidak benar-benar masuk akal untuk id tho

Sunting: Menghapus kutipan nyasar.

Mengenai :=operator:

Berbeda dengan itu =, :=operator tidak pernah diartikan sebagai operator pembanding. Ini berarti Anda dapat menggunakan :=dalam pernyataan SQL yang valid (tidak hanya dalam pernyataan SET) untuk menetapkan nilai ke variabel.

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

Mengenai kutipan pengidentifikasi backtick:

Karakter kutipan pengidentifikasi adalah backtick ("` ")

Jika ANSI_QUOTES SQL mode diaktifkan, itu juga diizinkan untuk mengutip pengidentifikasi dalam tanda kutip ganda

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

Michel Feldheim
sumber
7
... tidak sangat sederhana, setidaknya dibandingkan dengan TARIF :( coupla tutes:. net.tutsplus.com/tutorials/databases/... , sitepoint.com/how-to-create-mysql-triggers
Ben
ugh ini terlihat sangat tebal. Saya pikir saya lebih suka membuat tuple dengan python dan memeriksa nilai di sana alih-alih memasukkan ini.
OzzyTheGiant
Pertanyaan cepat: mengapa ini tidak berhasil tanpa mengatur DELIMITER?
ddz
52

CHECK kendala diabaikan oleh MySQL seperti yang dijelaskan dalam komentar sangat kecil dalam dokumen: CREATE TABLE

The CHECKklausul parsing tapi diabaikan oleh semua mesin penyimpanan.

ypercubeᵀᴹ
sumber
2
@thefiloe: Benar, di DBMS lain dengan implementasi CHECKkendala yang benar, jika CHECKdievaluasi FALSEmaka penyisipan (atau pembaruan) tidak dilakukan dan kesalahan terjadi.
ypercubeᵀᴹ
Diperbaiki di MariaDB (lihat jawaban ini stackoverflow.com/a/44333349 ).
Jérôme
@ Jérôme Saya tahu, saya punya beberapa (lebih baru) jawaban yang mencakup peningkatan di bidang ini (ada cara lain untuk menyelesaikan masalah ini, baik di MariaDB dan MySQL, sebelum MariaDB benar-benar menerapkan batasan CHECK). Yang saya tidak yakin adalah apakah saya harus pergi dan mengedit semua jawaban lama saya!
ypercubeᵀᴹ
Saya kira komentar saya dengan tautan ke jawaban yang lebih baru baik-baik saja. Atau lebih baik daripada tidak sama sekali. Mungkin saya seharusnya mengedit. Saya tidak bermaksud menekan Anda untuk melakukan apa pun.
Jérôme
1

Periksa kendala didukung pada versi 8.0.15 (belum dirilis)

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

[23 Jan 16:24] Paul Dubois

Diposting oleh pengembang: Diperbaiki pada 8.0.15.

Sebelumnya, MySQL mengizinkan bentuk terbatas dari sintaks kendala PERIKSA, tetapi menguraikan dan mengabaikannya. MySQL sekarang mengimplementasikan fitur inti dari tabel dan kolom PERIKSA kendala, untuk semua mesin penyimpanan. Batasan didefinisikan menggunakan pernyataan CREATE TABLE dan ALTER TABLE.

James
sumber
1

Perbarui ke MySQL 8.0.16 untuk menggunakan checks:

Pada MySQL 8.0.16, CREATE TABLE memungkinkan fitur inti dari kendala PERIKSA tabel dan kolom, untuk semua mesin penyimpanan. CREATE TABLE mengizinkan sintaks kendala PERIKSA berikut, untuk kendala tabel dan kendala kolom

MySQL Periksa Dokumentasi

sdlins
sumber
-2

coba dengan set sql_mode = 'STRICT_TRANS_TABLES'ATAUSET sql_mode='STRICT_ALL_TABLES'

Kanagu
sumber
2
actuall yang tidak membantu (MySQL 5.6) itu mencegah memasukkan data tipe palsu tetapi tidak memasukkan data yang tidak memenuhi CHECKkendala
petermeissner