Documentation Home
MySQL 8.4 Reference Manual
Related Documentation Download this Manual
PDF (US Ltr) - 39.8Mb
PDF (A4) - 39.9Mb
Man Pages (TGZ) - 257.9Kb
Man Pages (Zip) - 364.9Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


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

14.19.4 函数依赖检测

以下讨论提供了 MySQL 检测函数依赖的多种示例。这些示例使用以下记法:

{X} -> {Y}

理解为“X 唯一确定 Y,”,也就是说 Y 对于 X 是函数依赖。

这些示例使用了名为 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.*}

因此,co.name 依赖于 GROUP BY 列,并且查询是有效的。

可以使用 UNIQUE 索引代替主键,并且同样存在函数依赖关系。(这不适用于允许 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 的 pair (cl.CountryCode, cl.Language) 是一个二列主键,因此该列对唯一确定 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条件中进行等值测试时,这个测试是对称的。但是在外连接条件中进行等值测试时,这个测试不是对称的,因为表格扮演着不同的角色。

假设引用完整性已经意外地被破坏,并且存在一个countrylanguage行没有相应的行在country中。考虑前一个示例中的同一查询,但使用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值是 either 在匹配行中找到(由cl. CountryCode确定)或在没有匹配时使用NULL-补充(也由cl. CountryCode确定)。在每种情况下,这个关系适用:

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

cl. CountryCode自身是对{cl. CountryCodecl. Language}的函数依赖关系,该关系是一个主键。

如果在连接结果中co.CodeNULL-补充的,co.Name也将是这样。如果co.Code不是NULL-补充的,那么因为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.*}

实际上,对于cl所有NULL-补充行都被放入一个单独的组中(它们都有两个GROUP BY列等于NULL),并且在这个组内co.Name的值可以变化。该查询无效,MySQL 将 reject 它。

外连接中的函数依赖性因此与左或右侧的确定列相关联。如果有嵌套的外连接或连接条件不完全是等式比较,那么函数依赖性的确定将变得更加复杂。

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

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 understands this and uses this information, as described following.

这个查询显示了国家、它们的官方语言数量和城市数量,通过将视图与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 可以组合所有前述类型的函数依赖关系(键基于、等值基于、视图基于)来验证更复杂的查询。