Php 链接MySQL中的2个ID

Php 链接MySQL中的2个ID,php,mysql,mysql5,Php,Mysql,Mysql5,我有这张桌子 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; 我如何约束它,

我有这张桌子

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;
我如何约束它,使项目id只能在项目1\u id或项目2\u id中出现一次

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

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

这意味着您不需要链接表。您只需要在Item表中有一个LinkedItem列,该列上有一个唯一的约束。一旦Item2链接到Item1,Item1ID位于Item2行的linkedItemId中,则其他任何内容都无法链接到Item1

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

请注意,MySQL允许在唯一索引中使用多个空值,这与SQL Server不同,SQL Server使用过滤后的唯一索引忽略空值

来自MySQL 5.5

对于所有引擎,唯一索引允许包含NULL的列具有多个NULL值

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

这意味着您不需要链接表。您只需要在Item表中有一个LinkedItem列,该列上有一个唯一的约束。一旦Item2链接到Item1,Item1ID位于Item2行的linkedItemId中,则其他任何内容都无法链接到Item1

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

请注意,MySQL允许在唯一索引中使用多个空值,这与SQL Server不同,SQL Server使用过滤后的唯一索引忽略空值

来自MySQL 5.5

对于所有引擎,唯一索引允许包含NULL的列具有多个NULL值


我不认为INNODB可以在这方面实施这样的约束或MyIsam。我的建议是创建一个存储过程来处理insert。首先检查您的自定义约束需求,然后像往常一样插入,如果没有冲突。

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

您可以收缩唯一键,使其仅具有item1\u id。这意味着表定义了1:1关系,而不是1:n关系。此外,您可以删除自动增量主键,这些链接表中不需要它:

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,并且不需要任何值来存储未链接的项。两种设计的工作原理几乎相同,只是在Insert/Delete/Update语句中做了一些小的修改

不过,在这两种设计中,我们都可以有像:1->2,2->3,3->7这样的链接情侣。如果符合所需规格,两种设计都可以

然而,如果我们只希望项目只出现在链接的任意一侧的一对链接中,那么实现起来就比较困难

一种方法是确保links表中的所有插入都是通过一个过程完成的,该过程要么同时插入1,2和2,1对,要么失败,同样,对于必须处理2行的Delete/Update语句也是如此

其他更复杂的方法包括触发器或外来结构,如索引视图,这在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;
现在,您不能在links表中添加1->2,2->3,3->7行。

您可以将UNIQUE键收缩为只有item1\u id。这意味着该表定义了1:1关系,而不是1:n关系。此外,您可以删除自动增量主键,这些链接表中不需要它:

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,并且不需要任何值来存储未链接的项。两种设计的工作原理几乎相同,只是在Insert/Delete/Update语句中做了一些小的修改

不过,在这两种设计中,我们都可以有像:1->2,2->3,3->7这样的链接情侣。如果符合所需规格,两种设计都可以

然而,如果我们只希望项目只出现在链接的任意一侧的一对链接中,那么实现起来就比较困难

一种方法是确保links表中的所有插入都是通过一个过程完成的,该过程要么同时插入1,2和2,1对,要么失败,同样,对于必须处理2行的Delete/Update语句也是如此

其他更复杂的方法包括触发器或外来结构,如索引视图,这在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;

现在,您不能在links表中添加1->2,2->3,3->7行。

还有一个问题,即链接是否有明确的方向,即A-B与B-A是否不同

我想你需要测试一下,你可以用触发器来处理这两种情况。但是,我不知道有任何方法可以通过MySQL的过程语言显式抛出错误。既然您已经指定列不应为NULL,并且没有默认值,并且假设NEW是可写的,那么


您可能也需要更新前触发器,但代码的其余部分是相同的。

…还有一个问题,即链接是否有明确的方向,即a-B与B-a是否不同

我想你需要测试一下,你可以用触发器来处理这两种情况。但是,我不知道有任何方法可以通过MySQL的过程语言显式抛出错误。既然您已经指定列不应为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;

您可能也需要更新前触发器,但代码的其余部分是相同的。

试试看-这意味着您只能在链接已知或是伪条目的情况下添加记录-每个记录都必须链接到另一个或唯一的无意义值我同意第一条评论,即这不是一个好的解决方案。仅当每个项都有链接项时,此方法才能工作。当外键字段指向当前表的id时,如果将其设置为“唯一”,则该字段中不能有多个项具有空值。@Ray:MySQL不允许多个空值吗?与SQL Server不同,Sybase最多允许一个NULLMy bad。。。我将允许多个空值。请编辑您的答案,我将取消我的否决票。如果不对答案进行编辑,我将不会撤回。只有SQL Server将NULL视为具有唯一约束的列中的值,并且不允许有多个NULL。试试看-这将意味着您只能添加链接已知或是虚拟条目的记录-每个记录都必须链接我同意第一条评论,这不是一个好的解决方案。仅当每个项都有链接项时,此方法才能工作。当外键字段指向当前表的id时,如果将其设置为“唯一”,则该字段中不能有多个项具有空值。@Ray:MySQL不允许多个空值吗?与SQL Server不同,Sybase最多允许一个NULLMy bad。。。我将允许多个空值。请编辑您的答案,我将取消我的否决票。如果不编辑答案,我不会撤回。只有SQL Server将NULL视为具有唯一约束的列中的值,并且不允许多个NULL。我的答案也不会停止1->3,3->2,2->1。我还假设在链接表中方向并不重要。使用其他RDBMS中的计算列或工作检查约束更容易…我的答案也不会停止1->3,3->2,2->1。我还假设在链接表中方向并不重要。在其他RDBMS中使用计算列或使用工作检查约束更容易…如果item1和item2是两个单独的表,这将起作用。我认为其目的是它们都是相同的表“项”。在这种情况下,item.id可以位于item1\u id或item2\u id外键字段中。但是,如果不是,并且它们是两个独立的项表,则您的解决方案是正确的。@Ray:当两个项id都是同一个表的外键时,它应该可以正常工作。为什么不呢?如果item1和item2是两个单独的表,这将起作用。我认为其目的是它们都是相同的表“项”。在这种情况下,item.id可以位于item1\u id或item2\u id外键字段中。但是,如果不是,并且它们是两个独立的项表,则您的解决方案是正确的。@Ray:当两个项id都是同一个表的外键时,它应该可以正常工作。为什么不呢?