1

我有这张桌子

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只能在OR中出现一次item1_iditem2_id

因为我希望一个项目只链接到另一个项目..

4

4 回答 4

5

我希望一个项目只链接到另一个项目

这意味着您不需要链接表。您只需要linkedItemId在 Item 表中添加一个具有唯一约束的列。一旦 Item2 链接到 Item1(Item1ID 位于 Item2 行的 linkedItemId 中),则没有其他内容可以链接到 Item1。

此外,链接表不需要自己的代理键

编辑,请注意 MySQL 允许在唯一索引中使用多个 NULL(与 SQL Server 不同,您可以在其中使用过滤的唯一索引来忽略 NULL)

从 MySQL 5.5创建索引

对于所有引擎,UNIQUE 索引允许可以包含 NULL 的列有多个 NULL 值

于 2012-02-01T12:58:33.613 回答
1

我不认为 INNODB 可以强制执行这样的约束(或 MyIsam )。我的建议是创建一个存储过程来处理插入。首先检查您的自定义约束需求,如果没有冲突,则照常插入。

于 2012-02-01T12:58:36.077 回答
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

于 2012-02-01T13:03:57.170 回答
1

...还有一个问题是链接是否有明确的方向 - 即 AB 与 BA 不同吗?

认为(您需要对此进行测试)您可以使用触发器来处理这两种情况。但是,我不知道有任何方法可以使用 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;

(您可能也需要更新前触发器,但其余代码相同)。

于 2012-02-01T13:25:12.157 回答