2011-09-22 13 views
24

Tengo problemas con esta mesa¿Cómo agrego una restricción de verificación a una tabla?

CREATE TABLE `Participants` (
    `meetid` int(11) NOT NULL, 
    `pid` varchar(15) NOT NULL, 
    `status` char(1) DEFAULT NULL, 
    PRIMARY KEY (`meetid`,`pid`), 
    CONSTRAINT `participants_ibfk_1` FOREIGN KEY (`meetid`) REFERENCES `Meetings` (`meetid`) ON DELETE CASCADE 
    CONSTRAINT `participants_ibfk_2` CHECK (status IN ('a','d','u')) 
    CONSTRAINT `participants_ibfk_3` CHECK (pid IN (SELECT name FROM Rooms) OR pid IN (SELECT userid FROM People)) 
); 

Quiero tener una restricción de clave externa, y que funciona. Luego quiero agregar una restricción al atributo status, por lo que solo puede tomar los valores 'a', 'd' y 'u'. No me es posible configurar el campo como Enum o set.

¿Alguien me puede decir por qué este código no funciona en MySQL?

Respuesta

54

CHECK restricciones no son compatibles con MySQL. Puede definirlos, pero no hacen nada (a partir de MySQL 5.7).

Desde el manual:

La cláusula CHECK se analiza, pero ignorado por todos los motores de almacenamiento.

La solución alternativa es crear triggers, pero no son las cosas más fáciles de trabajar.

Si desea un RDBMS de código abierto que admita las restricciones CHECK, intente PostgreSQL. En realidad es una muy buena base de datos.

+0

Gracias por la respuesta corta y concreta –

+11

a veces me pregunto por qué alguien usa MySQL más - "Uy, lo siento, hemos decidido no implementar integridad de los datos!". Si tiene algún tipo de control de su RDBMS, y quiere código abierto, Postgres es el Camino. – Jordan

+0

Es cierto eso. MySQL no es una buena opción por varias razones y esta es una de ellas. – Dmitri

10

Junto a los factores desencadenantes, por restricciones simples como el que usted tiene:

CONSTRAINT `participants_ibfk_2` 
    CHECK status IN ('a','d','u') 

Se puede usar un Foreign Key de status a una tabla de referencia (ParticipantStatus con 3 filas: 'a','d','u'):

CONSTRAINT ParticipantStatus_Participant_fk 
    FOREIGN KEY (status) 
    REFERENCES ParticipantStatus(status) 
+1

Gracias por la sugerencia. –

-1

Aquí hay una forma de obtener los cheques que quería rápida y fácilmente:

drop database if exists gtest; 

create database if not exists gtest; 
use gtest; 

create table users (
    user_id  integer unsigned not null auto_increment primary key, 
    username  varchar(32) not null default '', 
    password  varchar(64) not null default '', 
    unique key ix_username (username) 
) Engine=InnoDB auto_increment 10001; 

create table owners (
    owner_id  integer unsigned not null auto_increment primary key, 
    ownername  varchar(32) not null default '', 
    unique key ix_ownername (ownername) 
) Engine=InnoDB auto_increment 5001; 

create table users_and_owners (
    id integer unsigned not null primary key, 
    name varchar(32) not null default '', 
    unique key ix_name(name) 
) Engine=InnoDB; 

create table p_status (
    a_status  char(1) not null primary key 
) Engine=InnoDB; 

create table people (
    person_id integer unsigned not null auto_increment primary key, 
    pid  integer unsigned not null, 
    name  varchar(32) not null default '', 
    status char(1) not null, 
    unique key ix_name (name), 
    foreign key people_ibfk_001 (pid) references users_and_owners(id), 
    foreign key people_ibfk_002 (status) references p_status (a_status) 
) Engine=InnoDB; 

create or replace view vw_users_and_owners as 
select 
    user_id id, 
    username name 
from users 
union 
select 
    owner_id id, 
    ownername name 
from owners 
order by id asc 
; 

create trigger newUser after insert on users for each row replace into users_and_owners select * from vw_users_and_owners; 
create trigger newOwner after insert on owners for each row replace into users_and_owners select * from vw_users_and_owners; 

insert into users (username, password) values 
('fred Smith', password('fredSmith')), 
('jack Sparrow', password('jackSparrow')), 
('Jim Beam', password('JimBeam')), 
('Ted Turner', password('TedTurner')) 
; 

insert into owners (ownername) values ('Tom Jones'),('Elvis Presley'),('Wally Lewis'),('Ted Turner'); 

insert into people (pid, name, status) values (5001, 'Tom Jones', 1),(10002,'jack Sparrow',1),(5002,'Elvis Presley',1); 
8

No entiendo por qué nadie aquí ha mencionado que VISTA CON CHECK OPTION puede ser una buena alternativa a la restricción CHECK en MySQL:

CREATE VIEW name_of_view AS SELECT * FROM your_table 
WHERE <condition> WITH [LOCAL | CASCADED] CHECK OPTION; 

Hay un documento en el sitio de MySQL: The View WITH CHECK OPTION Clause

DROP TABLE `Participants`; 

CREATE TABLE `Participants` (
    `meetid` int(11) NOT NULL, 
    `pid` varchar(15) NOT NULL, 
    `status` char(1) DEFAULT NULL check (status IN ('a','d','u')), 
    PRIMARY KEY (`meetid`,`pid`) 
); 

-- should work 
INSERT INTO `Participants` VALUES (1,1,'a'); 
-- should fail but doesn't because table check is not implemented in MySQL 
INSERT INTO `Participants` VALUES (2,1,'x'); 

DROP VIEW vParticipants; 
CREATE VIEW vParticipants AS 
    SELECT * FROM Participants WHERE status IN ('a','d','u') 
    WITH CHECK OPTION; 

-- should work 
INSERT INTO vParticipants VALUES (3,1,'a'); 
-- will fail because view uses a WITH CHECK OPTION 
INSERT INTO vParticipants VALUES (4,1,'x'); 
Cuestiones relacionadas