插入记录时对多个表进行约束检查

时间:2012-10-21 06:29:56

标签: mysql sql constraints alter

我有这样的数据库方案..

create table Photographer(
id int primary key references Person(id) on update cascade on delete cascade,
livesIn int not null references Location(id) on update cascade on delete no action
);
create table Specialty(
photographer int references Photographer(id) on update cascade on delete cascade,
type enum('portrait','landscape','sport'),
primary key(photographer, type)
);
create table Photo(
id int primary key,
takenAt timestamp not null,
takenBy int references Photographer(id) on update cascade on delete no action,
photographedAt int references Location(id) on update cascade on delete no action,
type enum('portrait','landscape','sport')
);

我必须限制数据库,以便摄影师有资格拍摄类型为t的照片,如果摄影师是摄影师的专长之一。

我的尝试无效。

/*Attempt 1*/
ALTER TABLE Photo ADD CONSTRAINT constraint_1      
CHECK (Photo.type in (SELECT Specialty.type FROM Specialty,Photo,Photographer 
WHERE Photo.takenBy = Photographer.id 
AND Photographer.id = Specialty.photographer 
AND Specialty.type = Photo.type));
/*Attempt 2 using exists instead of 'in'*/
ALTER TABLE Photo ADD CONSTRAINT constraint_1      
CHECK (exists (SELECT * FROM Specialty,Photo,Photographer 
WHERE Photo.takenBy = Photographer.id 
AND Photographer.id = Specialty.photographer 
AND Specialty.type = Photo.type));

我在这里做错了什么特别的错误?

1 个答案:

答案 0 :(得分:1)

正如ALTER TABLE Syntax所述:

  

CHECK子句被解析但被所有存储引擎忽略。见Section 13.1.17, “CREATE TABLE Syntax”。接受但忽略语法子句的原因是为了兼容性,以便更容易从其他SQL服务器移植代码,以及运行创建带引用的表的应用程序。请参阅Section 1.8.5, “MySQL Differences from Standard SQL”

您有几个选择:

  1. 使用FOREIGN KEY constraints,要求所有表使用InnoDB存储引擎:

    ALTER TABLE Specialty
      ADD FOREIGN KEY (photographer) REFERENCES Photographer (id);
    
    ALTER TABLE Photo
      ADD FOREIGN KEY (takenBy, type) REFERENCES Specialty (photographer, type);
    
  2. 使用触发器:

    CREATE TRIGGER foo1 BEFORE INSERT ON Photo FOR EACH ROW
    IF NOT EXISTS (
      SELECT *
      FROM   Specialty s JOIN Photographer p ON s.photographer = p.id
      WHERE  p.id = NEW.takenBy AND s.type = NEW.type
    ) THEN CALL raise.error;
    
    CREATE TRIGGER foo2 BEFORE UPDATE ON Photo FOR EACH ROW
    IF NOT EXISTS (
      SELECT *
      FROM   Specialty s JOIN Photographer p ON s.photographer = p.id
      WHERE  p.id = NEW.takenBy AND s.type = NEW.type
    ) THEN CALL raise.error;