Documentation Home
MySQL 8.3 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 40.8Mb
PDF (A4) - 40.9Mb
Man Pages (TGZ) - 294.0Kb
Man Pages (Zip) - 409.0Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb
Excerpts from this Manual

MySQL 8.3 Reference Manual  /  ...  /  Detection of Functional Dependence

14.19.4 函数依赖关系检测

以下讨论提供了 MySQL 检测函数依赖关系的多种方式。这些示例使用以下符号:

{X} -> {Y}

理解为 X 唯一确定 Y,,这也意味着 YX 上具有函数依赖关系。

这些示例使用 world 数据库,可以从 https://dev.mysql.com/doc/index-other.html 下载。您可以在同一页上找到安装数据库的详细信息。

从键派生出的函数依赖关系

以下查询选择每个国家的语言数量:

SELECT co.Name, COUNT(*)
FROM countrylanguage cl, country co
WHERE cl.CountryCode = co.Code
GROUP BY co.Code;

co.Codeco 的主键,因此 co 的所有列都在 co.Code 上具有函数依赖关系,如下所示:

{co.Code} -> {co.*}

因此,co.nameGROUP BY 列和查询有效。

可以使用 UNIQUE 索引覆盖 NOT NULL 列,而不是主键,并且相同的函数依赖关系将适用。(这不适用于允许 NULL 值的 UNIQUE 索引,因为它允许多个 NULL 值,从而失去了唯一性。)

从多列键和等式派生出的函数依赖关系

以下查询选择每个国家的所有语言和使用人数:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population / 100.0 AS SpokenBy
FROM countrylanguage cl, country co
WHERE cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

对 (cl.CountryCode, cl.Language) 是 cl 的复合主键,因此该列对唯一确定 cl 的所有列:

{cl.CountryCode, cl.Language} -> {cl.*}

此外,因为 WHERE 子句中的等式:

{cl.CountryCode} -> {co.Code}

并且,因为 co.Codeco 的主键:

{co.Code} -> {co.*}

“唯一确定”关系是传递的,因此:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

因此,查询有效。

与前一个示例相同,UNIQUE 键覆盖 NOT NULL 列可以代替主键。

可以使用 INNER JOIN 条件代替 WHERE。相同的函数依赖关系适用:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM countrylanguage cl INNER JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

函数依赖关系特殊情况

虽然 WHERE 子句或 INNER JOIN 条件中的等式测试是对称的,但外连接条件中的等式测试不是,因为表格扮演着不同的角色。

假设 referential integrity 已经被意外破坏,并且存在一个没有对应 country 行的 countrylanguage 行。考虑与前一个示例相同的查询,但使用 LEFT JOIN

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM countrylanguage cl LEFT JOIN country co
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

对于给定的 cl.CountryCode 值,join 结果中的 co.Code 值要么在匹配的行中找到(由 cl.CountryCode 确定),要么如果没有匹配则为空补充(也由 cl.CountryCode 确定)。在每种情况下,以下关系都适用:

{cl.CountryCode} -> {co.Code}

cl.CountryCode 本身对 {cl.CountryCode, cl.Language} 函数依赖,这是一个主键。

如果在 join 结果中 co.Code为空补充,那么 co.Name 也为空补充。如果 co.Code 不为空补充,那么因为 co.Code 是主键,它确定 co.Name。因此,在所有情况下:

{co.Code} -> {co.Name}

这就产生了:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

因此,查询是有效的。

然而,假设表格被交换,如在这个查询中:

SELECT co.Name, cl.Language,
cl.Percentage * co.Population/100.0 AS SpokenBy
FROM country co LEFT JOIN countrylanguage cl
ON cl.CountryCode = co.Code
GROUP BY cl.CountryCode, cl.Language;

现在这个关系不适用:

{cl.CountryCode, cl.Language} -> {cl.*,co.*}

实际上,所有为空补充的行都被分配到一个组中(它们都有相同的 GROUP BY 列为空),在这个组中 co.Name 的值可以变化。查询是无效的,MySQL 拒绝了它。

因此,在外连接中,函数依赖关系取决于确定列是否属于左侧或右侧的 LEFT JOIN。如果有嵌套的外连接或连接条件不仅仅是相等比较,那么确定函数依赖关系将变得更加复杂。

视图中的函数依赖关系

假设一个国家视图产生了它们的代码、名称的大写形式和官方语言的数量:

CREATE VIEW country2 AS
SELECT co.Code, UPPER(co.Name) AS UpperName,
COUNT(cl.Language) AS OfficialLanguages
FROM country AS co JOIN countrylanguage AS cl
ON cl.CountryCode = co.Code
WHERE cl.isOfficial = 'T'
GROUP BY co.Code;

这个定义是有效的,因为:

{co.Code} -> {co.*}

在视图结果中,第一个选择的列是 co.Code,它也是组列,因此确定了所有其他选择的表达式:

{country2.Code} -> {country2.*}

MySQL 理解了这一点,并使用了这些信息,如下所述。

这个查询显示了国家、它们的官方语言数量和城市数量,通过将视图与 city 表连接:

SELECT co2.Code, co2.UpperName, co2.OfficialLanguages,
COUNT(*) AS Cities
FROM country2 AS co2 JOIN city ci
ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

这个查询是有效的,因为之前所见:

{co2.Code} -> {co2.*}

MySQL 能够在视图结果中发现函数依赖关系,并使用该信息来验证使用视图的查询。如果 country2 是一个派生表(或公共表表达式),那么也是如此:

SELECT co2.Code, co2.UpperName, co2.OfficialLanguages,
COUNT(*) AS Cities
FROM
(
 SELECT co.Code, UPPER(co.Name) AS UpperName,
 COUNT(cl.Language) AS OfficialLanguages
 FROM country AS co JOIN countrylanguage AS cl
 ON cl.CountryCode=co.Code
 WHERE cl.isOfficial='T'
 GROUP BY co.Code
) AS co2
JOIN city ci ON ci.CountryCode = co2.Code
GROUP BY co2.Code;

函数依赖关系的组合

MySQL 能够组合所有前面的函数依赖关系类型(基于键、基于相等、基于视图)以验证更复杂的查询。