当前位置: 首页 > 面试题库 >

在SQL中,两个表相互引用是否可以?

鄢子平
2023-03-14
问题内容

在此系统中,我们存储产品,产品图像(产品可能有很多图像)和产品的默认图像。数据库:

CREATE TABLE  `products` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `NAME` varchar(255) NOT NULL,
  `DESCRIPTION` text NOT NULL,
  `ENABLED` tinyint(1) NOT NULL DEFAULT '1',
  `DATEADDED` datetime NOT NULL,
  `DEFAULT_PICTURE_ID` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`ID`),
  KEY `Index_2` (`DATEADDED`),
  KEY `FK_products_1` (`DEFAULT_PICTURE_ID`),
  CONSTRAINT `FK_products_1` FOREIGN KEY (`DEFAULT_PICTURE_ID`) REFERENCES `products_pictures` (`ID`) ON DELETE SET NULL ON UPDATE SET NULL
) ENGINE=InnoDB AUTO_INCREMENT=30 DEFAULT CHARSET=utf8;


CREATE TABLE  `products_pictures` (
  `ID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `IMG_PATH` varchar(255) NOT NULL,
  `PRODUCT_ID` int(10) unsigned NOT NULL,
  PRIMARY KEY (`ID`),
  KEY `FK_products_pictures_1` (`PRODUCT_ID`),
  CONSTRAINT `FK_products_pictures_1` FOREIGN KEY (`PRODUCT_ID`) REFERENCES `products` (`ID`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

如您所见,products_pictures.PRODUCT_ID -> products.IDproducts.DEFAULT_PICTURE_ID -> products_pictures.ID,是循环参考。可以吗


问题答案:

不,那不行。表之间的循环引用是混乱的。请参阅这篇(已有十年的历史)文章:SQL By
Design:循环参考

一些DBMS可以特别小心地处理这些问题,但是MySQL会遇到问题。

作为您的设计,第一选择是使两个FK之一为可空。这使您能够解决“鸡与蛋”问题(我应该首先插入哪个表?)。

但是您的代码有问题。它将允许产品具有默认图片,该图片将引用其他产品!

为避免此类错误,您的FK约束应为:

CONSTRAINT FK_products_1 
  FOREIGN KEY (id, default_picture_id) 
  REFERENCES products_pictures (product_id, id)
  ON DELETE RESTRICT                            --- the SET NULL options would 
  ON UPDATE RESTRICT                            --- lead to other issues

这将要求UNIQUE在表products_pictureson上有一个约束/索引,(product_id, id)以定义上述FK并正常工作。

另一种方法是Default_Picture_IDproduct表中删除列,然后在表中添加一IsDefault BITpicture。该解决方案的问题在于,如何仅允许每个产品使用一张图片,而其他产品禁用该图片。在SQL
Server(我认为在Postgres)中,可以使用部分索引来完成:

CREATE UNIQUE INDEX is_DefaultPicture 
  ON products_pictures (Product_ID)
  WHERE IsDefault = 1 ;

但是MySQL没有这种功能。

第三种方法,甚至可以将两个FK列都定义为NOT NULL使用可延期约束。这适用于PostgreSQL,我认为适用于Oracle。通过@Erwin检查此问题和答案:SQLAlchemy中的复杂外键约束( 所有键列NOT NULL 部分)。

MySQL中的约束不能被延迟。

第四种方法(我认为最干净)是删除该Default_Picture_ID列并添加另一个表。FK约束中没有循环路径,并且所有FK列都将NOT NULL使用此解决方案:

product_default_picture
----------------------
product_id          NOT NULL
default_picture_id  NOT NULL
PRIMARY KEY (product_id)
FOREIGN KEY (product_id, default_picture_id)
  REFERENCES products_pictures (product_id, id)

这也将需要UNIQUE在表约束/索引products_pictures(product_id, id)在溶液中1。

总而言之,对于MySQL,您有两种选择:

  • 选项1(可为空的FK列),并进行了上述更正以正确实施完整性

  • 选项4(没有可为空的FK列)



 类似资料:
  • 有时候在设计数据结构的时候,可能会遇到两个类需要相互引用的情形。比如类A有类型为B的成员,而类B又有类型为A的成员。 那么这种情形下,两个类的设计上需要注意什么呢? 同一文件 尝试方案 将A和B的定义都放在一个文件中,例如: #include <iostream> class A { public: A() { aa_ = 'A'; } char aa_;

  • 我有两个类,一个被设计用来包含另一个 然而,我不能相互引用类类型(和),只能是其中之一。 我怎样才能在彼此之间引用这两个类类型呢?否则最好的方法是什么?

  • PDPage对象是否包含对其所属PDDocument的引用 换句话说,PDPage是否了解其PDDocument<在应用程序的某个地方,我有一个文档列表 这些文档被合并到一个新的PDDocument中: 然后将此PDI文档分成10个包: 我现在的问题是: 如果我循环遍历列表中这些拆分的PDDocuments的页面,是否有办法知道页面最初属于哪个PDDocument? 另外,如果你有一个PDPage

  • 问题内容: 所以,我有两个实体引用对方,。 如果已删除,则必须将其删除,但在仍有引用的情况下不能删除。 这是我得到的两个约束: 我现在要删除一个(和相应的)… 呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜呜… 是的,我正在尝试删除的血腥条目引用了它… (我知道这是因为上有一个唯一的约束) 看起来如果我将fk设置为,我可以删除该条目,但是这似乎并不是我呼吸的那个家伙想要的,这就是“如果您删除了它,也删除了

  • 问题内容: 我的数据库包含三个表叫,和。链接表仅包含两列,即对象记录的标识和数据记录的标识。 我想从链接到一个给定对象标识的位置复制数据,并在不同的给定对象标识中插入相应的记录。 我 可以 通过选择一个表变量,并为每次迭代进行两次插入来循环执行此操作。 这是最好的方法吗? 编辑 :我想避免循环的原因有两个,第一个是我很懒,并且循环/临时表需要更多的代码,更多的代码意味着有更多的地方出错,第二个原因

  • 我知道在elasticsearch中没有连接索引的选项,但我需要找到一种方法来解决这个问题: 我有两个索引,比如A,B IndexA的信息像field d1、field d2、field d3 IndexB有field d4、field d5、field d6 如果我将按查询字段5(在本例中为“test”)进行搜索,我希望树中的所有关系如下: 匹配IndexA中与“field2”(来自IndexA