暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

MySQL的函数和运算符 - 聚合函数 - 检测功能依赖

数据库杂货铺 2021-09-22
695
检测功能依赖
 
下面的讨论提供了几个 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.Code co 的主键,所以 co 的所有列在功能上都依赖于它,如下所示:
       
        {co.Code} -> {co.*}
         
        因此,co.name 在功能上依赖于 GROUP BY 列,查询是有效的。
         
        可以使用 NOT NULL 列上的 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.CountryCode, cl.Language) 对儿是 cl 的两列复合主键,因此这2列唯一地确定 cl 的所有列:
           
            {cl.CountryCode, cl.Language} -> {cl.*}
             
            此外,由于 WHERE 子句中的相等性:
             
              {cl.CountryCode} -> {co.Code}
               
              并且,因为 co.Code co 的主键:
               
                {co.Code} -> {co.*}
                 
                “唯一决定”关系是可传递的,因此:
                 
                  {cl.CountryCode, cl.Language} -> {cl.*,co.*}
                   
                  因此,查询是有效的。
                   
                  与前面的示例一样,可以使用 NOT NULL 列上的 UNIQUE 键来代替主键。
                   
                  可以使用 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 值。co.Code 的值要么在匹配的行中找到(cl.CountryCode 确定),要么没有匹配,由 NULL 填补(也由 cl.CountryCode 确定)。在每种情况下,这种关系都适用于:
                       
                        {cl.CountryCode} -> {co.Code}
                         
                        cl.CountryCode 本身在功能上依赖于 {cl.CountryCode, cl.Language},此两列是主键。
                         
                        如果连接结果中 co.Code 填补为 NULLco.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 会拒绝。
                                 
                                因此,外部联接中的功能依赖性与行列式列属于 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 能够结合前面所有类型的功能依赖(基于键、基于相等、基于视图)来验证更复杂的查询。
                                             
                                             
                                             
                                             
                                             
                                            官方文档:
                                            https://dev.mysql.com/doc/refman/8.0/en/group-by-functional-dependence.html
                                            文章转载自数据库杂货铺,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                                            评论