Young87

当前位置:首页 >个人收藏

用SQL进行集合运算


集合论是SQL语言的根基——因为它的这个特性,SQL也被称为面向集合语言

顾名思义,集合运算符的参数是集合,从数据库实现层面上来说就是表或者视图,集合运算有以下几个注意事项:

  • SQL能操作具有重复行的集合,可以通过可选项ALL来支持

    一般的集合论是不允许集合里存在重复元素的,因此集合{1,1,2,3,3,3}和集合{1,2,3}被视为相同的集合。但是关系数据库里的表允许存在重复的行,称为多重集合

    集合运算符为了排除掉重复行,默认地会发生排序,而加上可选项ALL之后,就不会再排序,所以性能会有提升。 这是非常有效的用于优化查询性能的方法,所以如果不关心结果是否存在重复行,或者确定结果里不会产生重复行,加上可选项ALL会更好

  • 集合运算符有优先级

    标准SQL规定,INTERSECT比UNION和EXCEPT优先级更高。因此,当同时使用UNION和INTERSECT,又想让UNION优先执行时,必须使用括号明确地指定运算顺序

  • 各个DBMS提供商在集合运算的实现程度上参差不齐

  • 除法运算没有标准定义


比较表和表:检查集合相等性

-- 假设事先已经确认了tbl_A和tbl_B的行数是一样的,可采用以下方法判定:
SELECT COUNT(*) AS row_cnt
FROM (SELECT *
     FROM tbl_A
     UNION
     SELECT *
     FROM tbl_B) TMP;

对于任意的表S,均有 S UNION S = S,这是UNION的一个非常重要的性质,在数学上我们称之为幂等性(indempotency)

-- 除了UNION之外,另一个具有幂等性的运算符就是INTERSECT

-- 两张表相等时返回“相等”,否则返回“不相等”
SELECT CASE WHEN COUNT(*) = 0
            THEN '相等'
            ELSE '不相等' END AS result
FROM ((SELECT * FROM tbl_A
      UNION
      SELECT * FROM tbl_B)
     EXCEPT
     (SELECT * FROM tbl_A
     INTERSECT
     SELECT * FROM tbl_B)) TMP;
     
-- 注意:MySQL中还无法使用INTERSECT和EXCEPT

用差集实现关系除法运算

SQL中还没有能直接进行关系除法运算的运算符,因此,为了进行除法运算,必须自己实现。方法比较多,其中具有代表性的是以下三个:

  1. 嵌套使用NOT EXISTS
  2. 使用HAVING子句转换成一对一关系
  3. 把除法变成减法

下面主要介绍一下方法3

在这里插入图片描述
在这里插入图片描述

-- 用求差集的方法进行关系除法运算(有余数)
SELECT DISTINCT emp
FROM EmpSkills ES1
WHERE NOT EXISTS
    (SELECT skill 
    FROM Skills
    EXCEPT
    SELECT skill
    FROM EmpSkills ES2
    WHERE ES1.emp = ES2.emp);

寻找相等的子集

在这里插入图片描述

-- 生成供应商的全部集合(非等值连接 + 聚合(为了去除重复))
SELECT SP1.sup AS s1, SP2.sup AS s2
FROM SupParts SP1, SupParts SP2
WHERE SP1.sup < SP2.sup
GROUP BY SP1.sup, SP2.sup;


SELECT SP1.sup AS s1, SP2.sup AS s2
FROM SupParts SP1, SupParts SP2
WHERE SP1.sup < SP2.sup
AND SP1.part = SP2.part      -- 条件1:经营同种类型的零件
GROUP BY SP1.sup, SP2.sup
HAVING COUNT(*) = (SELECT COUNT(*)     -- 条件2:经营的零件种类数相同
                  FROM SupParts SP3
                  WHERE SP3.sup = SP1.sup)
   AND  COUNT(*) = (SELECT COUNT(*)
                  FROM SupParts SP4
                  WHERE SP4.sup = SP2.sup);

用于删除重复行的高效SQL

-- 没有主键

-- 使用关联子查询
DELETE FROM Products
WHERE rowid < (SELECT MAX(P2.rowid)
              FROM Products P2
              WHERE Products.name = P2.name
              AND Products.price = P2.price);
              
-- 用于删除重复行的高效SQL语句(1):通过EXCEPT求补集
DELETE FROM Products
WHERE rowid IN (SELECT rowid
               FROM Products
               EXCEPT 
               SELECT MAX(rowid)
               FROM Products
               GROUP BY name, price);
               
-- 删除重复行的高效SQL语句(2):通过NOT IN求补集
DELETE FROM Products
WHERE rowid NOT IN (SELECT MAX(rowid)
                   FROM Products
                   GROUP BY name, price)

除特别声明,本站所有文章均为原创,如需转载请以超级链接形式注明出处:SmartCat's Blog

上一篇: 这份数据清洗checklist,让开发过程更加高效

下一篇: HAVING子句的力量

精华推荐