我有这张桌子
CREATE TABLE IF NOT EXISTS `links` (
`link_id` int(20) NOT NULL AUTO_INCREMENT,
`item1_id` int(20) NOT NULL,
`item2_id` int(20) NOT NULL,
PRIMARY KEY (`link_id`),
UNIQUE KEY `item_id` (`item1_id`,`item2_id`)
) ENGINE=InnoDB;
如何限制它,以便the item_id
只能在item1_id
或item2_id
因为我希望一个项目只链接到另一个项目..
答案 0 :(得分:5)
我想要一个项目只链接到另一个项目
这意味着您不需要链接表。您只需在Item表中使用linkedItemId
列,并在其上添加唯一约束。一旦Item2链接到Item1(Item1ID在Item2行的linkedItemId中),那么其他任何东西都不能链接到Item1。
此外,链接表不需要自己的代理键
编辑,请注意MySQL允许在唯一索引中使用多个NULL(与SQL Server不同,在SQL Server中,您使用过滤的唯一索引来忽略NULL)
来自MySQL 5.5 CREATE INDEX
对于所有引擎,UNIQUE索引允许可以包含NULL的列的多个NULL值
答案 1 :(得分:1)
我不认为INNODB可以强制执行这样的约束(或MyIsam)。我的建议是创建一个存储过程来处理插入。首先检查您的自定义约束需求,然后如果没有冲突则照常插入。
答案 2 :(得分:1)
您可以将UNIQUE KEY
缩小为仅item1_id
。这意味着该表定义了1:1
关系,而不是1:n
关系。此外,您可以删除auto_increment
主键,这些“链接”表中不需要它:
CREATE TABLE IF NOT EXISTS links (
item1_id int(20) NOT NULL,
item2_id int(20) NOT NULL,
PRIMARY KEY (item1_id),
FOREIGN KEY (item1_id) --- I assume you have these 2
REFERENCES item (item_id), --- Foreign Keys, too
FOREIGN KEY (item2_id)
REFERENCES item (item_id)
) ENGINE=InnoDB;
这和@ gbn的答案之间的区别在于,这不允许Null,并且不需要任何存储未链接的项目。两种设计的工作方式几乎相同,只需对插入/删除/更新语句进行少量修改即可。
在这两种设计中,我们可以将以下情侣联系起来:(1 -> 2)
,(2 -> 3)
,(3 -> 7)
。如果符合要求的规格,两种设计都可以。
但是,如果我们只希望项目只出现在链接的任何一侧的一对链接中,则实现起来比较困难。
一种方法是确保links
表中的所有插入都是通过插入(1, 2)
和(2, 1)
对或失败的过程完成的(对于删除/更新类似)必须处理2行的语句。
其他更复杂的方法涉及触发器(或异常结构,如索引视图,MySQL中不可用)。
如果你想要一个标准化的设计,也有这种方法(复杂但没有触发器):
CREATE TABLE IF NOT EXISTS link_help (
item1_id int(20) NOT NULL,
item2_id int(20) NOT NULL,
PRIMARY KEY (item1_id),
FOREIGN KEY (item1_id)
REFERENCES item (item_id),
FOREIGN KEY (item2_id)
REFERENCES item (item_id),
UNIQUE KEY (item1_id, item2_id) --- this will be needed below
) ENGINE=InnoDB;
CREATE TABLE IF NOT EXISTS links (
item1_id int(20) NOT NULL,
item2_id int(20) NOT NULL,
PRIMARY KEY (item1_id),
FOREIGN KEY (item1_id, item2_id)
REFERENCES link_help (item1_id, item2_id),
FOREIGN KEY (item2_id, item1_id) --- notice the different
REFERENCES link_help (item1_id, item2_id) --- order here
) ENGINE=InnoDB;
现在,您无法在(1 -> 2)
表格中添加(2 -> 3)
,(3 -> 7)
,links
行。
答案 3 :(得分:1)
......还有一个问题是链接是否有明确的方向 - 即A-B是否与B-A不同?
我认为(你需要测试一下)你可以使用触发器处理这两种情况。但是我不知道任何可以用MySQL的过程语言显式抛出错误的方法。既然你已经指定列应该是NOT NULL而没有默认值,并假设NEW是可写的,那么....
CREATE TRIGGER ins_link BEFORE INSERT on links
FOR EACH ROW
BEGIN
IF (NEW.item1_id = NEW.item2_id) THEN
NEW.item2_id=NULL; /* subsequent INSERT will fail */
END IF
/* if you want AB=BA.... */
IF (NEW.item1_id > NEW.item2_id) THEN
@tempvar=NEW.item1_id;
NEW.item1_id=NEW.item2_id;
NEW.item2_id=@tempvar;
END IF;
END;
(您可能还需要更新之前的触发器,但代码的其余部分相同)。