对数据库表中行的限制

时间:2011-10-18 10:08:40

标签: mysql database database-design relational-database

我有三张桌子:

BallId  Color

ball_1  red
ball_2  red
ball_3  blue
ball_4  green
ball_5  green

.......

BoxId  Color

box_1  green
box_2  green
box_3  red
.......

BoxId  BallId

box_1  ball4
box_1  ball5
box_3  ball2

我想在BoxId,BallId表上强制颜色关系,是否可能是示意图?

4 个答案:

答案 0 :(得分:3)

我不太确定你的最终目标是什么。

如果您只是想确保底部表中的BoxIdBallId必须存在于前两个表中,那么您可以使用FOREIGN KEYs(又名“参照完整性”)。 / p>

---编辑---

基于其他评论/回复,我发现您确实希望确保通过第三个表连接的2行始终具有相同的颜色,但断开连接的行仍然可以拥有自己的颜色。

如果是这样,那么你可以“滥用”这样的键:

Ball:
    BallId PK, AK1
    Color  AK1

Box:
    BoxId  PK, AK1
    Color  AK1

BallInBox
    BallId PK
    BoxId  PK
    Color
    FK (BallId, Color) references Ball
    FK (BoxId, Color) references Box

这是实际的DDL SQL:

delimiter $$

CREATE TABLE Ball (
  BallId varchar(45) NOT NULL,
  Color varchar(45),
  PRIMARY KEY (BallId),
  UNIQUE KEY Ball_AK1 (BallId, Color)
)$$

CREATE TABLE Box (
  BoxId varchar(45) NOT NULL,
  Color varchar(45),
  PRIMARY KEY (BoxId),
  UNIQUE KEY Box_AK1 (BoxId, Color)
)$$

CREATE TABLE BallInBox (
  BallId varchar(45) NOT NULL,
  BoxId varchar(45) NOT NULL,
  Color varchar(45),
  PRIMARY KEY (BallId, BoxId),
  CONSTRAINT BallInBox_FK1 FOREIGN KEY (BallId, Color) REFERENCES Ball (BallId, Color),
  CONSTRAINT BallInBox_FK2 FOREIGN KEY (BoxId, Color) REFERENCES Box (BoxId, Color)
)$$

BTW,这允许“基础”表和“连接”表中的NULL颜色。如果不是你想要的话,很容易添加NOT NULL约束。

答案 1 :(得分:2)

一种方法(虽然它不是严格的“原理图”)是在第三个表上有一个插入触发器,用于检查输入的球/盒的颜色,如果它们不相同则抛出异常< / p>

答案 2 :(得分:1)

我认为,就关系理论而言,这个问题的答案如下:你在这里真正说的是你有一套盒子和一组球,每个球都放在一个盒子里。盒子和球每个都有一种颜色,球只能在一个匹配颜色的盒子里。但是将球的颜色存储在球桌中是一个设计错误。相反,你应该只存储每个球所在的盒子,然后你知道球是什么颜色,因为你可以检查它所存储的盒子的颜色(使用连接)。

所以,不,没有你可以指定的约束来强制执行你想要的关系,但那是因为你以错误的方式解决这个问题。你不应该在球表中有Color列。

编辑:以上假设每个球必须在一个盒子里。 OP澄清说不是每个球都需要在一个盒子里。这似乎是一个更难的问题,因为在这种情况下你不能依靠盒子表来跟踪球的颜色。我可以看到一些不同的解决方案,但都不是完美的。

  1. 使用您的原始设计,并接受它不会为您提供强制执行约束的简单方法。
  2. 创建一个新表“unboxed_ball”,用于存储不在盒子中的球,并且有一个“颜色”列来记录球的颜色。盒子里的球可以在原始的球桌上找到;在这个新表中可以找到不在盒子里的球。要查询所有已装箱和未装箱的球,您需要执行UNION。
  3. 将“假盒子”添加到盒子表中,每种颜色一个,这种颜色的未装箱的球被认为是“内部”(虽然盒子确实不存在)。如果这个“假盒子”不具备的盒子的其他属性,这可能不太实用。

答案 3 :(得分:1)

可以使用复合外键通过数据库执行此操作:

create table ball
(id int unsigned not null primary key auto_increment,
color varchar(10)) engine=InnoDB;

create table box
(id int unsigned not null primary key auto_increment,
color varchar(10)) engine=InnoDB;

create table boxBallRule    
(ballId int unsigned not null,
boxId int unsigned not null,
PRIMARY KEY (ballId,boxId),
CONSTRAINT `boxBallRule_box_fk1` FOREIGN KEY (boxId) references `box` (id),
CONSTRAINT `boxBallRule_ball_fk1` FOREIGN KEY (ballId) references `ball` (id)
) engine=InnoDB;

create table boxBall
(id int unsigned primary key auto_increment not null,
ballId int unsigned not null,
boxId int unsigned not null,
CONSTRAINT `boxBallColorRule_fk1` FOREIGN KEY (ballId,boxId) references boxBallRule(ballId,boxId)
) engine=InnoDB;

然后,您可以在boxBallRule表中的哪个框中存储允许的球。任何不符合“允许”框与球关系的boxBall表中的插入都将失败。因此:

insert into ball (color) values ('red');
insert into ball (color) values ('blue');
insert into ball (color) values ('green');

insert into box (color) values ('red');
insert into box (color) values ('blue');
insert into box (color) values ('green');

insert into boxBallRule (ballId,boxId) values ((select id from ball where color = 'red'),(select id from box where color = 'red'));
insert into boxBallRule (ballId,boxId) values ((select id from ball where color = 'blue'),(select id from box where color = 'blue'));
insert into boxBallRule (ballId,boxId) values ((select id from ball where color = 'green'),(select id from box where color = 'green'));

-- Let's try and put a red ball in a green box. 
-- The DB should not allow us to do this!
insert into boxBall (ballId,boxId) values 
((select id from ball where color = 'red'),
 (select id from box where color = 'green'));

最后一个语句应该失败,因为它违反了boxBallRule表上的复合外键。