美文网首页
Java EE之旅10-数据库基础(4)

Java EE之旅10-数据库基础(4)

作者: 小楠总 | 来源:发表于2018-01-31 09:50 被阅读45次

    为什么要进行拆表

    比如说一张学生表,里面有一个字段为分数:

    image.png

    我们知道,一个学生可以考多门课程,有多门课程的分数,那么这时候就需要添加多个重复的数据了;而且这里并不能区分是什么课程。那么这时候就需要进行表拆分了:

    image.png

    进行表拆分的优点是:

    1. 实现项目的具体需求
    2. 避免大量冗余数据,提高数据的查询效率。

    注意:表并不是拆分得越仔细越好,否则工作量会增加

    多表查询

    既然有了表拆分,那么就会有多表查询。多表查询有如下几种:

    1. 合并结果集;UNION 、 UNION ALL
    2. 连接查询
      内连接 [INNER] JOIN ON
      外连接 OUTER JOIN ON
      左外连接 LEFT [OUTER] JOIN
      右外连接 RIGHT [OUTER] JOIN
      全外连接(MySQL不支持)FULL JOIN
      自然连接 NATURAL JOIN
    3. 子查询
    4. 自连接

    1 合并结果集

    1. 作用:合并结果集就是把两个select语句的查询结果合并到一起!
    2. 合并结果集有两种方式:
      UNION:去除重复记录,例如:SELECT * FROM t1 UNION SELECT * FROM t2;
      UNION ALL:不去除重复记录,例如:SELECT * FROM t1 UNION ALL SELECT * FROM t2。
    3. 要求:被合并的两个结果:列数、列类型必须相同(不相同的时候,通过SELECT关键字去筛选需要的列)。

    相关的图例如下:

    image.png

    例子:

    create table a(
        id int,
        name varchar(10),
        score int
    );
    
    create table b(
        name varchar(10),
        score int
    );
    
    insert into a values(1,'a',10),(2,'b',20),(3,'c',30);
    insert into b values('a',10),('b',20),('d',40);
    
    去除重复记录
    select name,score from a union select * from b;
    
    不去除重复记录
    select name,score from a union all select * from b;
    

    2 连接查询(重点)

    连接不限于两张表,连接查询也可以是三张、四张,甚至N张表的连接查询。直接查询多张表会产生笛卡尔积,通常连接查询不可能需要整个笛卡尔积,而只是需要其中一部分,那么这时就需要使用条件来去除不需要的记录。这个条件大多数情况下都是使用主外键关系去除,这时候就需要N-1个查询条件。

    两张表的连接查询一定有一个主外键关系,三张表的连接查询就一定有两个主外键关系,所以在大家不是很熟悉连接查询时,首先要学会去除无用笛卡尔积,那么就是用主外键关系作为条件来处理。如果两张表的查询,那么至少有一个主外键条件,三张表连接至少有两个主外键条件。

    
    下面将以两个表为例进行讲解:
    
    CREATE TABLE student(
        sid INT PRIMARY KEY,
        name VARCHAR(50) NOT NULL,
        sex VARCHAR(10) DEFAULT '男'
    );
    
    CREATE TABLE score(
        id INT,
        score INT,
        sid INT , -- 外键列的数据类型一定要与主键的类型一致
        CONSTRAINT fk_score_sid FOREIGN KEY (sid) REFERENCES student(id)
    );
    
    2.1 内连接查询
    
    -- 我们通常写的连接查询又叫做99查询法,核心思想就是主外键的连接:
    select s.sid,s.name,c.score from student s , score c where s.sid=c.sid;
    
    -- 也可以写成标准的内连接查询(核心就是inner join on关键字)
    select s.sid,s.name,c.score from student s inner join score c on s.sid=c.sid;
    
    注意:内连接查询中,inner可以省略
    
    2.2 外连接查询
    
    外连接查询分为左、右外连接查询:
    
    -- 左外连接查询(参照student表,student有的,即使score中对应数据为NULL,也会查询得到)
    select s.sid,s.name,c.score from student s left outter join score c on s.sid=c.sid;
    
    -- 右外连接查询(参照score表)
    select s.sid,s.name,c.score from student s right outter join score c on s.sid=c.sid;
    
    注意:左右外连接查询中,outter可以省略,其中MySQL不支持全外连接查询。
    
    2.3 自然连接查询
    
    大家也都知道,连接查询会产生无用笛卡尔积,我们通常使用主外键关系等式来去除它。而自然连接无需你去给出主外键等式,它会自动找到这一等式,其实就是相当于内连接查询。例如:
    
    select * from student natural join score;
    
    

    3 子查询

    子查询就是嵌套查询,即SELECT中包含SELECT,如果一条语句中存在两个,或两个以上SELECT,那么就是子查询语句了。

    子查询出现的位置:

    where后,作为条为被查询的一条件的一部分;
    from后,作表;
    
    当子查询出现在where后作为条件时,还可以使用如下关键字(用得比较少):
    any
    all
    

    子查询结果集的形式:

    单行单列(用于条件)
    单行多列(用于条件)
    多行单列(用于条件)
    多行多列(用于表)
    
    
    例子,我们还是以这个数据作为例子:
    
    员工表emp:
    
        create table emp(
            empno    int,
            ename    varchar(50),
            job      varchar(50),
            mgr      int,
            hiredate date,
            sal      decimal(7,2),
            comm     decimal(7,2),
            deptno   int
        ); 
        insert into emp values(7369,'smith','clerk',7902,'1980-12-17',800,null,20);
        insert into emp values(7499,'allen','salesman',7698,'1981-02-20',1600,300,30);
        insert into emp values(7521,'ward','salesman',7698,'1981-02-22',1250,500,30);
        insert into emp values(7566,'jones','manager',7839,'1981-04-02',2975,null,20);
        insert into emp values(7654,'martin','salesman',7698,'1981-09-28',1250,1400,30);
        insert into emp values(7698,'blake','manager',7839,'1981-05-01',2850,null,30);
        insert into emp values(7782,'clark','manager',7839,'1981-06-09',2450,null,10);
        insert into emp values(7788,'scott','analyst',7566,'1987-04-19',3000,null,20);
        insert into emp values(7839,'king','president',null,'1981-11-17',5000,null,10);
        insert into emp values(7844,'turner','salesman',7698,'1981-09-08',1500,0,30);
        insert into emp values(7876,'adams','clerk',7788,'1987-05-23',1100,null,20);
        insert into emp values(7900,'james','clerk',7698,'1981-12-03',950,null,30);
        insert into emp values(7902,'ford','analyst',7566,'1981-12-03',3000,null,20);
        insert into emp values(7934,'miller','clerk',7782,'1982-01-23',1300,null,10);
        
    部门表dept:
    
        create table dept(
            deptno    int,
            dname     varchar(14),
            loc       varchar(13)
        );
        insert into dept values(10, 'ACCOUNTING', 'NEW YORK');
        insert into dept values(20, 'RESEARCH', 'DALLAS');
        insert into dept values(30, 'SALES', 'CHICAGO');
        insert into dept values(40, 'OPERATIONS', 'BOSTON');
    
    
    -- 查询工资高于scott的员工信息
    SELECT * FROM emp WHERE sal>(SELECT sal FROM emp WHERE ename='scott');
    
    -- 工资高于30号部门所有人的员工信息
    SELECT * FROM emp WHERE sal>(SELECT MAX(sal) FROM emp WHERE deptno=30);
    
    -- 查询工作和工资与scott完全相同的员工信息
    SELECT * FROM emp WHERE (job,sal) IN (SELECT job,sal FROM emp WHERE ename='scott')
    
    -- 有2个以上直接下属的员工信息
    SELECT * FROM emp WHERE empno IN(SELECT mgr FROM emp GROUP BY mgr HAVING COUNT(mgr)>=2);
    
    

    4 自连接查询

    
    自连接查询的核心是把自己看成两张表。
    
    -- 求7369员工编号、姓名、经理编号和经理姓名
    SELECT e1.empno , e1.ename,e2.mgr,e2.ename 
            FROM emp e1, emp e2 
            WHERE e1.mgr = e2.empno AND e1.empno = 7369;
    
    
    

    相关文章

      网友评论

          本文标题:Java EE之旅10-数据库基础(4)

          本文链接:https://www.haomeiwen.com/subject/hlxrixtx.html