数据库笔记(十)——关系代数

基本运算

每一种基本运算的结果都是一个新的关系,可以用这个关系继续参与运算,借此便可进行复杂的运算

  • 选择运算(select)==>相当于SQL语句中的WHERE子句的职能

    • 格式:σ选择谓词(关系)

    • 举个栗子:

      • σSAL>1000(EMP)

      • 上式表示取出查询工资大于1000的所有员工的信息

      • 等价于下面的SQL语句
        1
        2
        3
        SELECT *
        FROM EMP
        WHERE SAL > 1000
    • 选择谓词的分类

      • 比较:=、≠、<、≤、>和≥
      • 连词:and(∧)、or(∨)和not(¬)==>可以将多个谓词合并成一个大的谓词
      • 可以包括两个属性(字段的比较):σCOMM>SAL(EMP)表示抽成大于工资的人
  • 投影运算(project)==>相当于SQL语句中的SELECT子句的职能

    • 格式:∏字段序列(关系)

    • 举个栗子

      • ENAME,SAL(EMP)

      • 上式表示查看所有员工的姓名和工资

      • 等价于下面的SQL语句
        1
        2
        SELECT ENAME, SAL
        FROM EMP
  • 关系的组合运算==>就像SQL中select、where子句那样的组合效果

    • 举个栗子

      • ENAME,SALSAL>1000(EMP))

      • 上面的式子求出了所有工资大于1000的员工的名字和工资(实际上就是将σSAL>1000(EMP)执行的结果当做一个临时的关系,参与了投影运算得到的)

      • 等价于下面的SQL语句
        1
        2
        3
        SELECT ENAME, SAL
        FROM EMP
        WHERE SAL > 1000
    • 事实关系的组合运算就是那么简单,分析的时候把每个简单运算的结果当做一个新的关系参与后面的运算,这样一层层剥开来,再复杂的语句也变得容易分析

  • 并运算(union)==>相当于SQL中UNION关键字的职能

    • 格式:(关系r)∪(关系s)

    • 举个栗子

      • ENAME,SALSAL>1000(EMP)) ∪ ∏ENAME,SALCOMM>300(EMP))

      • 上面的式子求出了所有工资大于1000或抽成大于300的员工的姓名和工资,等价于下面的SQL语句

        1
        2
        3
        4
        5
        6
        7
        SELECT ENAME, SAL
        FROM EMP
        WHERE SAL > 1000
        UNION
        SELECT ENAME, SAL
        FROM EMP
        WHERE COMM > 300
    • 几点需要额外注意的

      • 此处的并运算是集合运算,所以结果是去重的,结果集中不存在重复的元组(而在SQL语句中,指定UNION ALL是可以保留重复的

      • 关系r与关系s必须是同元的,即它们的属性的数目要求必须相同(这就和SQL语句中UNION使用的时候要求上下两个语句的字段数相同是一样的意思)

      • 关系r和关系s对应位置的属性域应该是类型兼容的(同样和SQL中UNION使用时,每个对应位置字段类型兼容是一样的意思)
  • 集合的差运算(set-defference)==>相当于SQL语句中的EXCEPT

    • 格式:(关系r)-(关系s)

    • 举个栗子

      • ENAME,SALSAL>1000(EMP)) - ∏ENAME,SALCOMM>300(EMP))
      • 上面的式子表示工资大于1000但抽成不大于300的员工的姓名和工资,等价于下面的SQL语句
        1
        2
        3
        4
        5
        6
        7
        SELECT ENAME, SAL
        FROM EMP
        WHERE SAL > 1000
        EXCEPT
        SELECT ENAME, SAL
        FROM EMP
        WHERE COMM > 300
    • 几点需要额外注意的

      • 此处的注意同上面的并运算的注意事项
  • 笛卡尔积运算(Cartesian-product)==>等价于SQL语句中两个表进行笛卡尔积(全匹配)得到的结果,即SQL中进行多表连接时不指定连接条件的情况

    • 格式:(关系r)×(关系)

    • 举个栗子:

      • EMP × DEPT
      • 上面的式子表示两个表进行全匹配,等价于下面的SQL语句
        1
        2
        SELECT *
        FROM EMP, DEPT
    • 下面两个式子是等价的

      • ENAME,DNAMEEMP.DEPTNO=DEPT.DEPTNOJOB=”MANAGER”(EMP×DEPT)))
      • ENAME,DNAMEEMP.DEPTNO=DEPT.DEPTNO((σJOB=”MANAGER”(EMP))×DEPT)
      • 下面是对这两个式子的SQL转化,转化之后就一目了然了
        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        -- 对应第一个式子
        SELECT ENAME, DNAME
        FROM EMP JOIN DEPT ON EMP.DEPTNO = DEPT.DEPTNO
        WHERE JOB = 'MANAGER'

        -- 对应第二个式子
        SELECT ENAME, DNAME
        FROM DEPT JOIN (SELECT *
        FROM EMP
        WHERE JOB = 'MANAGER')
        ON EMP.DEPTNO = DEPT.DEPTNO
  • 更名运算(rename)==>等价于SQL语句中as的职能

    • 格式:ρX(A1,A2,…,An)(E)==>表示的是将关系E更名为X,Ai表示的是给E的第i个字段指定别名

    • 举个栗子
      • ENAME,DNAMEe.DEPTNO=d.DEPTNOJOB=”MANAGER”e(EMP)×ρd(DEPT))))
      • 上面式子含义就不解释了,是上面举的栗子,只是引入了更名运算符,它等价于下面的SQL语句
        1
        2
        3
        SELECT ENAME, DNAME
        FROM EMP e JOIN DEPT d ON e.DEPTNO = d.DEPTNO
        WHERE JOB = 'MANAGER'
  • 来,学习完上面的基本运算,来做个实际的栗子,要求找到员工表中的最高工资(因为目前还没有介绍类似SQL中组函数的操作,后面会介绍。所以通过以下方式来实现)

    • step1: 找到所有不是最高工资的人
      • e1.SALe1.sal < e2.sale1(EMP)×ρe2(EMP)))
    • step2: 用所有的员工减去上面的员工,即得到最高工资
      • SAL(EMP) - ∏e1.SALe1.sal < e2.sale1(EMP)×ρe2(EMP)))
  • 在书写关系运算表达式的时候可以用序列号代替字段名(但是不直观,不常用,一般不用)

    • 举个栗子
      • $6$6 < $14(EMP×EMP))
      • 等价于下面的运算
      • e1.SALe1.sal < e2.sale1(EMP)×ρe2(EMP)))

附加运算

附加运算是由基本运算组成的,不能增强基本运算的运算能力,但是能简化运算

  • 集合交运算(intersection)==>相当于SQL语句中INTERSECT关键字的职能

    • 格式:(关系r)∩(关系s)

    • 因为集合交运算是可以由前面的基本运算组合产生的,所以把它归到附加运算
      • A ∩ B <=> A - (A - B)
    • 举个栗子
      • ENAME,SALSAL>1000(EMP)) ∩ ∏ENAME,SALCOMM>300(EMP))
      • 上面的式子表示工资大于1000并且抽成大于300的员工的姓名和工资,等价于下面的SQL语句
        1
        2
        3
        4
        5
        6
        7
        SELECT ENAME, SAL
        FROM EMP
        WHERE SAL > 1000
        INTERSECT
        SELECT ENAME, SAL
        FROM EMP
        WHERE COMM > 300
  • 自然连接(natural join)==> 相当于SQL语句中的NATURAL JOIN

    • 格式:(关系)⋈(关系)

    • 自然连接的形式化定义

      • r,s是两个关系
      • R,S是上面两个关系对应的关系模式(其实就是上述两个关系各自的属性列表)
      • R ∩ S 表示r和s的同名属性列表
      • R ∪ S 表示出现在r或s上的属性名列表(是一个集合,不包同名属性,存在同名属性会去重)
      • R - S 表示出现在R上,但不出现在S上的属性名列表
      • 则可做如下定义
      • r⋈s = ∏R∪Sr.A1=s.A1 ∧ r.A2=s.A2 ∧ … ∧ r.An=s.An(r×s)) ,其中 R∩S={A1, A2, …, An}
    • 举个栗子
      • name, course_id(instructor ⋈ teaches)
      • 上面的式子列出了所有老师的名字以及其所授课程的id,等价于下面的SQL语句
        1
        2
        SELECT name, course_id
        FROM intructor natural join teaches

    ps: 两个关系模式执行自然连接以后属性的排布顺序:

    • 排在最前面的是两个关系模式相同的属性
    • 其次是只属于第一个关系模式的属性
    • 最后是只属于第二个关系模式的属性

      !!!所以所两个关系模式进行自然连接以后,总的属性的个数是减少了,具体减少的个数等于同名属性的个数

  • theta连接==>是带限定条件的笛卡尔积

    • 格式:(关系)⋈Θ(关系)

    • 形式化定义:
      • r ⋈Θ s = σΘ(r × s)
    • 举个栗子
      • name, course_id(instructor ⋈instructor.ID = teaches.ID ∧ instructor.salary > 5000 teaches)
      • 上面的式子表示列出所有工资大于5000的老师的名字以及其所授课程的id, 等价于下面的SQL语句
        1
        2
        3
        4
        -- 使用 join...on 的时候 on 后面写连接条件,然后将其它条件放在where里
        SELECT name, course_id
        FROM instructor join teaches on instructor.ID = teaches.ID
        WHERE instructor.salary > 5000
  • 除运算(division)

    这个在书上没讲,是老师上课的时候补充的

    • 格式:(关系)÷(关系)

    • 形式化定义:
      R÷S = ∏R∪S( ( ∏R-S(r) × S ) - ∏R-S, S(r) )
    • 笔者还有一篇介绍用SQL实现关系代数中除运算的文章=>点我传送
    • 解释起来挺麻烦的,这边给出一个博客链接:点我传送
  • 赋值运算

    就是将一个关系表达式的结果赋值取一个临时的名字,就相当于定义了一个临时关系。这个操作就相当于SQL中with语句的职能

    • 格式: temp_name ← 关系表达式

    • 举个栗子:
      temp1 ← R × S
      temp2 ← σr.A1=s.A1 ∧ r.A2=s.A2 ∧ … ∧ r.An=s.An(temp1)
      result = ∏R∪S(temp2)
    • 上面的式子等价于: result = r⋈s
  • 外连接运算

    • 左外连:⟕
    • 右外连:⟖
    • 全外连:⟗

扩展运算

扩展运算是不能用基本的关系代数运算来实现的一类查询,可以满足复杂的查询需求

  • 广义投影(Generalized-projection)

    与基本运算中的投影运算相比,就是多了允许在选择列表中出现表达式(在基本运算中的投影的选择列表中只能出现字段)

    • 格式:∏F1, F2, … , Fn(E)

      • 其中F1, F2, … , Fn可以是字段或者是表达式
      • E代表一个关系
    • 举个栗子:

      • name, sal * 1.2(instructor)

      • 上面的式子表示查出所有老师的名字,以及涨了20%以后的工资,等价于下面的SQL语句

        1
        2
        SELECT name, sal * 1.2
        FROM instructor
  • 聚集函数(Aggregation function)

    聚集函数的符号表示是用书写体G,这边就直接用G指代了

    聚集函数是输入值的一个汇聚,以多个值作为输入,将一个单一的值作为返回结果

    多重集:使用聚集函数对其进行操作的汇集中,一个值可以出现多次,值出现的顺序是无关紧要的。这样的汇集称为多重集(就比方说统计一个员工表中员工的数量,然后我们通过统计员工的名字来统计,即便是同名的员工我们也是计算的)

    • 格式: G1, G2, … , GnGF1(A1), F2(A2), …, Fn(An)(E)

      • 其中前面的G1, G2, … , Gn表示的是分组条件
      • 后面的F1(A1), F2(A2), …, Fn(An)是聚集函数表达式列表
      • Fi(i = 1, 2, …, n)表示聚集函数:sum、count、average、max、min
      • A1, A2, … , An代表字段
    • 举个栗子:

      • A1, A2Gsum(A3)(∏A1, A2, …, AnP(r1×r2×…×rm)) )
      • 等价于下面的SQL语句
        1
        2
        3
        4
        SELECT A1, A2, sum(A3)
        FROM r1, r2, ..., rm
        WHERE P
        GROUP BY A1, A2
    • 上面的聚集函数在进行计算的时候采用的都是多重集,也就是相同的值可以多次重复计算(也就是在执行聚集函数的时候是不去重计算),如果要去重计算的话就要采用下面的几个函数写法

      • sum_distinct
      • count_distinct
      • averag_distinct
      • max_distinct
      • min_distinct
    • 举个栗子:
      • A1, A2Gsum_distinct(A3)(∏A1, A2, …, AnP(r1×r2×…×rm)) )
      • 上面的式子等价于下面的SQL语句
        1
        2
        3
        4
        SELECT A1, A2, sum(distinct A3)
        FROM r1, r2, ..., rm
        WHERE P
        GROUP BY A1, A2
坚持原创技术分享,您的支持将鼓励我继续创作!