2011-09-22 28 views
24

Tôi gặp rắc rối với bảng nàyLàm cách nào để thêm ràng buộc kiểm tra vào bảng?

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)) 
); 

Tôi muốn có một ràng buộc khoá ngoại, và làm việc. Sau đó, tôi muốn thêm một ràng buộc vào thuộc tính status để nó chỉ có thể lấy các giá trị 'a', 'd' và 'u'. Tôi không thể đặt trường là Enum hoặc set.

Có ai cho tôi biết tại sao mã này không hoạt động trong MySQL không?

Trả lời

54

CHECK các ràng buộc không được MySQL hỗ trợ. Bạn có thể định nghĩa chúng, nhưng chúng không làm gì cả (như của MySQL 5.7).

Từ manual:

Mệnh CHECK được phân tách nhưng bỏ qua tất cả các công cụ lưu trữ.

Cách giải quyết là tạo triggers, nhưng chúng không phải là thứ dễ làm việc nhất.

Nếu bạn muốn RDBMS nguồn mở hỗ trợ các ràng buộc CHECK, hãy thử PostgreSQL. Nó thực sự là một cơ sở dữ liệu rất tốt.

+0

Cảm ơn bạn đã trả lời ngắn gọn và cụ thể –

+11

Đôi khi tôi tự hỏi tại sao ai sử dụng MySQL nữa - "oops, xin lỗi, chúng tôi quyết định không thực hiện toàn vẹn dữ liệu!". Nếu bạn có bất kỳ loại điều khiển nào của RDBMS của mình và bạn muốn có nguồn mở, Postgres là The Way. – Jordan

+0

Đúng vậy. MySQL không phải là một lựa chọn tốt vì nhiều lý do và đây là một trong số đó. – Dmitri

10

Bên cạnh trigger, vì những hạn chế đơn giản như một trong những bạn có:

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

bạn có thể sử dụng một Foreign Key từ status vào một bảng tham chiếu (ParticipantStatus với 3 hàng: 'a','d','u'):

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

Cảm ơn bạn đã đề xuất. –

-1

Dưới đây là cách nhận séc bạn muốn nhanh chóng và dễ dàng:

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

Tôi không hiểu tại sao không ai ở đây đã nói rằng XEM WITH CHECK OPTION có thể là một lựa chọn tốt để các ràng buộc kiểm tra trong MySQL:

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

Có một doc trên trang web 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'); 
Các vấn đề liên quan