SQL:通过外键指定唯一约束并高效查询

SQL: Specifying a unique constraint through a foreign key and efficiently querying it

架构

我在 MySQL 中有以下数据库模式:

主题

例如(5, Algebra, algebra), (6, Java, java) ...

module_sections

例如

(1, 5, Algebra Basics, 1), (2, 6, Introduction to Programming, 1), (3, 6, Variables, 2) ...

模块

例如 (1, 1, Collecting like terms, collecting-like-terms, 1), (2, 2, What is Programming?, what-is-programming, 1), (3, 2, Installing Java, installing-java, 2) ...

数据库模式解释

上述数据库显示 3 tables。每个topic有很多module_sections,每个module_sections有很多modules

上面的示例数据可以写成这样的列表:

每个 topic 在 table.

中必须有唯一的 nameslug

每个 module section 必须有一个唯一的 name topic。 (例如,我们可以在 AlgebraJava 中都有一个名为 Introduction 的部分,因为它们都是不同的主题)

每个 module 对于那个 topic 必须是唯一的(不仅仅是那个部分)。例如,我们不能在 Introduction to ProgrammingVariables 下同时包含模块 What is Programming?(因为它们都在同一主题中),但我们可以在 [=33] 下包含 Arithmetic =] 和 Introduction to Programming (因为它们在不同的主题中)。不幸的是,我无法在架构中指定此特定约束。

查询

我希望高效地执行以下查询:

问题

总结一下,我面临的问题如下:

随时提出对模式的更改建议:

我正在为 PHP 框架使用 Laravel。

How to specify the integrity constraint: unique([module_section.topic_id, slug]) in the modules table.

你不能。 SQL 不支持诸如此类的间接约束。您只能限制直接出现在约束适用的 table 中的值。

您的问题源于您选择使用单列代理键,再加上您对 slug 唯一性的要求与您对模块唯一性的要求不一致。使用这样的结构,无法表达您想放置的 SQL 约束。作为替代方案,您可以在 module table 上创建插入和更新触发器,以在模块 slugs 上强制执行所需条件。

另一方面,如果 module_section 的 PK 是复合的,并且 topic_id 作为其列之一,您可以编写一个约束,就像您想象的那样。然后 module 中引用模块部分的 FK 将在其中包含主题 ID,您可以使用约束来实现您想要的。