# 12.20.4 检测功能依赖

下面的讨论提供了 MySQL 检测功能依赖关系的几个示例。示例使用此表示法:

{X} -> {Y}

将其理解为“X唯一确定,”这也意味着*在功能上取决于X*.

示例使用世界数据库,可以从https://dev.mysql.com/doc/index-other.html (opens new window).您可以在同一页面上找到有关如何安装数据库的详细信息。

# 从键派生的功能依赖

以下查询为每个国家/地区选择口语计数:

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

代码是一个主键合作, 所以所有列合作在功能上依赖于它,如使用此符号表示:

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

因此,同名在功能上取决于通过...分组列并且查询有效。

一种独特索引超过非空可以使用列代替主键,并且将应用相同的功能依赖性。(这对于一个独特允许的索引空值值,因为它允许多个空值值,在这种情况下,唯一性就会丢失。)

# 从多列键和从

平等

此查询为每个国家/地区选择所有使用语言的列表以及使用这些语言的人数:

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.CountryCode, cl.Language} -> {cl.*}

此外,由于平等在哪里条款:

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

而且,因为代码是主键合作

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

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

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

结果,查询是有效的。

与前面的示例一样,一个独特关键非空可以使用列代替主键。

一个内部联接可以使用条件代替在哪里.相同的功能依赖项适用:

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;

# 功能依赖特例

而在一个平等测试在哪里条件或内部联接条件是对称的,外连接条件中的相等性测试不是,因为表扮演不同的角色。

假设参照完整性被意外破坏并且存在一行国家语言没有对应的行国家.考虑与上一个示例中相同的查询,但使用左连接

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, 的价值代码在连接结果中要么在匹配的行中找到(由cl.CountryCode) 或者是空值- 如果没有匹配则补充(也由cl.CountryCode)。在每种情况下,这种关系都适用:

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

cl.CountryCode本身在功能上依赖于 {cl.CountryCode,分类语言} 这是一个主键。

如果在连接结果中代码空值-补充,同名也是。如果代码不是空值-互补,然后因为代码是主键,它决定同名.因此,在所有情况下:

{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.*}

的确,所有空值-为完成的行分类被放入一个组中(他们都有通过...分组列等于空值),并且在这个组内的值同名可以变化。查询无效,MySQL 拒绝它。

因此,外连接中的功能依赖与行列式列属于左侧还是右侧相关联。左连接.如果存在嵌套的外部连接或连接条件不完全由相等比较组成,则函数依赖的确定会变得更加复杂。

# 功能依赖和视图

假设一个国家的视图产生了他们的代码、他们的大写名字,以及他们有多少不同的官方语言:

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.*}

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

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

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

此查询通过将视图与城市桌子:

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 能够发现视图结果中的功能依赖关系,并使用它来验证使用该视图的查询。如果国家2是派生表(或公用表表达式),如:

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 能够结合前面所有类型的函数依赖(基于键、基于相等、基于视图)来验证更复杂的查询。