12.20.4 Detection of Functional Dependence功能依赖性检测

The following discussion provides several examples of the ways in which MySQL detects functional dependencies. 下面的讨论提供了几个MySQL检测函数依赖关系的方法示例。The examples use this notation:示例使用此符号:

{X} -> {Y}

Understand this as X uniquely determines Y, which also means that Y is functionally dependent on X.把它理解为“X唯一地决定Y”,这也意味着Y在功能上依赖于X

The examples use the world database, which can be downloaded from https://dev.mysql.com/doc/index-other.html. 这些示例使用的是world数据库,可以从https://dev.mysql.com/doc/index-other.html下载到。You can find details on how to install the database on the same page.您可以在同一页上找到有关如何安装数据库的详细信息。

Functional Dependencies Derived from Keys从键派生的函数依赖项

The following query selects, for each country, a count of spoken languages:以下查询为每个国家选择一个口语计数:

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

co.Code is a primary key of co, so all columns of co are functionally dependent on it, as expressed using this notation:co.Codeco的主键,因此co的所有列在功能上都依赖于它,如使用以下符号表示的:

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

Thus, co.name is functionally dependent on GROUP BY columns and the query is valid.因此,co.name在功能上依赖于GROUP BY列,查询是有效的。

A UNIQUE index over a NOT NULL column could be used instead of a primary key and the same functional dependence would apply. 可以使用NOT NULL列上的UNIQUE索引代替主键,并应用相同的函数依赖关系。(This is not true for a UNIQUE index that permits NULL values because it permits multiple NULL values and in that case uniqueness is lost.)(对于允许空值的UNIQUE索引,这是不正确的,因为它允许多个NULL值,在这种情况下,唯一性将丢失。)

Functional Dependencies Derived from Multiple-Column Keys and from Equalities从多个列键和等式派生的函数依赖项

This query selects, for each country, a list of all spoken languages and how many people speak them:此查询为每个国家选择所有口语的列表以及说这些语言的人数:

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;

The pair (cl.CountryCode, cl.Language) is a two-column composite primary key of cl, so that column pair uniquely determines all columns of cl:

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

Moreover, because of the equality in the WHERE clause:此外,由于WHERE子句中的平等性:

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

And, because co.Code is primary key of co:又因为co.Codeco的主键:

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

Uniquely determines relationships are transitive, therefore:“唯一决定”关系是可传递的,因此:

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

As a result, the query is valid.因此,查询是有效的。

As with the previous example, a UNIQUE key over NOT NULL columns could be used instead of a primary key.与前面的示例一样,可以使用NOT NULL列上的UNIQUE键来代替主键。

An INNER JOIN condition can be used instead of WHERE. 可以使用INNER JOIN条件代替WHEREThe same functional dependencies apply:同样的函数依赖关系也适用于:

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;

Functional Dependency Special Cases函数依赖特例

Whereas an equality test in a WHERE condition or INNER JOIN condition is symmetric, an equality test in an outer join condition is not, because tables play different roles.WHERE条件或INNER JOIN条件中的相等性测试是对称的,而OUTER JOIN条件中的相等性测试不是对称的,因为表扮演不同的角色。

Assume that referential integrity has been accidentally broken and there exists a row of countrylanguage without a corresponding row in country. 假设引用完整性被意外破坏,并且存在countrylanguage行,而country中没有相应的行。Consider the same query as in the previous example, but with a 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;

For a given value of cl.CountryCode, the value of co.Code in the join result is either found in a matching row (determined by cl.CountryCode) or is NULL-complemented if there is no match (also determined by cl.CountryCode). 对于给定的cl.CountryCode值,联接结果中co.Code的值要么在匹配行中找到(由cl.CountryCode确定),要么在不匹配的情况下补为空(也由cl.CountryCode确定)。In each case, this relationship applies:在每种情况下,这种关系都适用于:

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

cl.CountryCode is itself functionally dependent on {cl.CountryCode, cl.Language} which is a primary key.cl.CountryCode本身在功能上依赖于{cl.CountryCode, cl.Language},后者是主键。

If in the join result co.Code is NULL-complemented, co.Name is as well. 如果在连接结果中co.Code是空的,那么co.Name也是空的。If co.Code is not NULL-complemented, then because co.Code is a primary key, it determines co.Name. 如果co.Code不是空的补码,那么因为co.Code是主键,所以它决定co.NameTherefore, in all cases:因此,在所有情况下:

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

Which yields:由此产生:

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

As a result, the query is valid.因此,查询是有效的。

However, suppose that the tables are swapped, as in this query:但是,假设表已交换,如以下查询中所示:

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;

Now this relationship does not apply:现在这种关系不适用:

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

Indeed, all NULL-complemented rows made for cl is put into a single group (they have both GROUP BY columns equal to NULL), and inside this group the value of co.Name can vary. 实际上,为cl生成的所有NULL补码行都放在一个组中(它们的GROUP BY列都等于NULL),并且在这个组中co.Name的值可以不同。The query is invalid and MySQL rejects it.该查询无效,MySQL拒绝该查询。

Functional dependence in outer joins is thus linked to whether determinant columns belong to the left or right side of the LEFT JOIN. 因此,外部联接中的函数依赖性与行列式列属于LEFT JOIN的左侧还是右侧有关。Determination of functional dependence becomes more complex if there are nested outer joins or the join condition does not consist entirely of equality comparisons.如果存在嵌套的外部联接或联接条件不完全由相等比较组成,则函数依赖性的确定将变得更加复杂。

Functional Dependencies and Views功能依赖项和视图

Suppose that a view on countries produces their code, their name in uppercase, and how many different official languages they have:假设一个国家的观点产生了他们的代码,他们的名字是大写的,他们有多少种不同的官方语言:

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;

This definition is valid because:此定义有效,因为:

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

In the view result, the first selected column is co.Code, which is also the group column and thus determines all other selected expressions:在视图结果中,第一个选定的列是co.Code,它也是成组列,因此确定所有其他选定表达式:

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

MySQL understands this and uses this information, as described following.MySQL理解并使用这些信息,如下所述。

This query displays countries, how many different official languages they have, and how many cities they have, by joining the view with the city table:此查询通过将视图与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;

This query is valid because, as seen previously:此查询有效,因为如前所述:

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

MySQL is able to discover a functional dependency in the result of a view and use that to validate a query which uses the view. MySQL能够发现视图结果中的函数依赖关系,并使用它来验证使用该视图的查询。The same would be true if country2 were a derived table (or common table expression), as in:如果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;

Combinations of Functional Dependencies函数依赖项的组合

MySQL is able to combine all of the preceding types of functional dependencies (key based, equality based, view based) to validate more complex queries.MySQL能够结合前面所有类型的函数依赖(基于键、基于等式、基于视图)来验证更复杂的查询。