2022-08-16 数据库查询语言之——-DQL

重点,DQL是我们每天都要接触编写最多也是最难的SQL,该语言用来查询记录,不会修改数据库和表结构。

构建数据库

创建一张student表:

DROP TABLE IF EXISTS student;
CREATE TABLE student (
    id INT(10) PRIMARY KEY,
    name VARCHAR(10),
    age INT(10) NOT NULL,
    gender VARCHAR(2)
);

构建一张course表:

DROP TABLE IF EXISTS course;
CREATE TABLE course(
    id INT(10) PRIMARY KEY,
    name VARCHAR(10),
    t_id INT(10)
);

构建一张teacher表:

DROP TABLE IF EXISTS teacher;
CREATE TABLE teacher(
    id INT(10) PRIMARY KEY,
    name VARCHAR(10)
);

构建一个score表:

DROP TABLE IF EXISTS score;
CREATE TABLE scores(
    s_id INT(10),
    score INT(10),
    c_id INT(10),
    PRIMARY KEY(s_id,c_id)
);

表格填充数据:

insert into  student (id,name,age,gender)VALUES(1,'小明',19,'男'),(2,'小红',19,'男'),(3,'小刚',24,'男'),(4,'小龙',11,'男'),(5,'小丽',18,'男'),(6,'小军',18,'女'),(7,'小航',16,'男'),(8,'小亮',23,'男'),(9,'小杰',22,'女'),(10,'小虎',21,'男');

insert into  course (id,name,t_id)VALUES(1,'数学',1),(2,'语文',2),(3,'c++',3),(4,'java',4),(5,'php',null);

insert into  teacher (id,name)VALUES(1,'Tom'),(2,'Jerry'),(3,'Tony'),(4,'Jack'),(5,'Rose');

insert into  scores (s_id,score,c_id)VALUES(1,80,1);
insert into  scores (s_id,score,c_id)VALUES(1,56,2);
insert into  scores (s_id,score,c_id)VALUES(1,95,3);
insert into  scores (s_id,score,c_id)VALUES(1,30,4);
insert into  scores (s_id,score,c_id)VALUES(1,76,5);

insert into  scores (s_id,score,c_id)VALUES(2,35,1);
insert into  scores (s_id,score,c_id)VALUES(2,86,2);
insert into  scores (s_id,score,c_id)VALUES(2,45,3);
insert into  scores (s_id,score,c_id)VALUES(2,94,4);
insert into  scores (s_id,score,c_id)VALUES(2,79,5);

insert into  scores (s_id,score,c_id)VALUES(3,65,2);
insert into  scores (s_id,score,c_id)VALUES(3,85,3);
insert into  scores (s_id,score,c_id)VALUES(3,37,4);
insert into  scores (s_id,score,c_id)VALUES(3,79,5);

insert into  scores (s_id,score,c_id)VALUES(4,66,1);
insert into  scores (s_id,score,c_id)VALUES(4,39,2);
insert into  scores (s_id,score,c_id)VALUES(4,85,3);

insert into  scores (s_id,score,c_id)VALUES(5,66,2);
insert into  scores (s_id,score,c_id)VALUES(5,89,3);
insert into  scores (s_id,score,c_id)VALUES(5,74,4);

insert into  scores (s_id,score,c_id)VALUES(6,80,1);
insert into  scores (s_id,score,c_id)VALUES(6,56,2);
insert into  scores (s_id,score,c_id)VALUES(6,95,3);
insert into  scores (s_id,score,c_id)VALUES(6,30,4);
insert into  scores (s_id,score,c_id)VALUES(6,76,5);

insert into  scores (s_id,score,c_id)VALUES(7,35,1);
insert into  scores (s_id,score,c_id)VALUES(7,86,2);
insert into  scores (s_id,score,c_id)VALUES(7,45,3);
insert into  scores (s_id,score,c_id)VALUES(7,94,4);
insert into  scores (s_id,score,c_id)VALUES(7,79,5);

insert into  scores (s_id,score,c_id)VALUES(8,65,2);
insert into  scores (s_id,score,c_id)VALUES(8,85,3);
insert into  scores (s_id,score,c_id)VALUES(8,37,4);
insert into  scores (s_id,score,c_id)VALUES(8,79,5);

insert into  scores (s_id,score,c_id)VALUES(9,66,1);
insert into  scores (s_id,score,c_id)VALUES(9,39,2);
insert into  scores (s_id,score,c_id)VALUES(9,85,3);
insert into  scores (s_id,score,c_id)VALUES(9,79,5);

insert into  scores (s_id,score,c_id)VALUES(10,66,2);
insert into  scores (s_id,score,c_id)VALUES(10,89,3);
insert into  scores (s_id,score,c_id)VALUES(10,74,4);
insert into  scores (s_id,score,c_id)VALUES(10,79,5);

单表查询

查询所有列:

select * from 表名;
select * from student;

查询指定的列:

select id,name,age,gender from student;
select id,name,age from student;

补充:开发中,严禁使用 select *

如果表中有完全重复的记录只显示一次,在查询的列之前加上 distinct

select DISTINCT name from book;
select id,name,age/10 from student;

注意:我们写的所有的查询语句,最终执行的结果,都是生成一张虚拟表。

select id,name,sal+1000 from employee;

注意:

  1. null值和任何值做计算都为null,需要用到函数 ifnull()函数。 select IFNULL(sal,0) + 1000 from employee;如果薪资是空,则为0。
  2. 将字符串做加减乘除运算,会把字符串当0处理。

我们可以为该列指定别名,因为我们可能会在查询过程中重复该列的名称,可能该名称不够简洁,或者该列名称不符合我们的要求。

[En]

We can give the column an alias, because we are likely to repeat the column name during the query, maybe the name is not concise enough, or the column name does not meet our requirements.

select id 编号,name 姓名,age 年龄,gender 性别 from student;
select id as 编号,name as 姓名,age as 年龄,gender as 性别 from student;

条件查询:在后面添加 where指定条件

select * from student where id = 3;
select * from student where id in (1,3,5);
select * from student where id > 2;
select * from student where id BETWEEN 3 and 5;
select * from student where id BETWEEN 6 and 7 or age > 20;

模糊查询:我想查一下所有姓张的人。

[En]

Fuzzy query: I want to check all the people surnamed Zhang.

select * from student where name like '张%';
select * from student where name like '张_';
select * from student where name like '%明%';
select * from student where name like '_明_';

通配符: _下划线代表一个字符, %百分号代表任意个字符。

  • 升序
select * from student ORDER BY age ASC;
-- ASC是可以省略
  • 降序
select * from student ORDER BY age DESC;
  • 使用多列作为排序条件:当第一个排序条件相同时,根据第二列排序条件进行排序(如果第二列仍然相同,。)
    [En]

    use multiple columns as the sort condition: when the first sort condition is the same, sort according to the second column sort condition (if the second column is still the same,.)*

select * from student ORDER BY age asc,id desc;

举例:
创建一张用户表,id,username,password。
几乎所有的表都会有两个字段,create_time,update_time。
几乎所有的查询都会按照update_time降序排列。

查询满足条件的记录行数,后边可以跟where条件。

如果满足条件的列值为空,则不进行统计。

[En]

If the column value that meets the condition is empty, no statistics will be made.

如果我们想要计算真实和有效的记录的数量,最好不要使用空列。

[En]

If we want to count the number of real and valid records, it is best not to use empty columns.

  • count(*)
  • count(主键)(推荐)
  • count(1)(不推荐)
select count(列名) from 表名;
select count(id) from student where gender='男';

查询满足条件的记录中的最大值,后面可以跟where条件。

select max(age) from student where gender='女';

查询满足条件的记录中的最小值,后面可以跟where条件。

select MIN(age) from student where gender='男';

查询满足条件的记录的和,后面可以跟where条件。

select sum(age) from student where gender='男';

查询满足条件的记录的平均数,后面可以跟where条件。

select avg(score) from scores where c_id = 3;

顾名思义:分组查询就是对原始数据进行分组。

[En]

As the name implies: grouping query is to group the original data.

举例:
班上的学生按性别分组,统计男生和女生的平均年龄。

[En]

The students in the class are divided into groups according to gender, and the average ages of boys and girls are counted.

select 分组列名,聚合函数1,聚合函数2... from 表名 group by 该分组列名;

分组要使用关键词 group by,后面可以是一列,也可以是多个列,分组后查询的列只能是分组的列,或者是使用了聚合函数的其他的列,剩余列不能单独使用。

-- 根据性别分组,查看每一组的平均年龄和最大年龄
select gender,avg(age),max(age) from student group by gender;
-- 根据专业号分组,查看每一个专业的平均分
select c_id,avg(score) from scores group by c_id;

我们可以这样理解:一旦分组发生,我们查询的结果只能是所有男孩的平均年龄和最大值,而不是特定男孩的数据。

[En]

We can understand it this way: once grouping occurs, the result of our query can only be the average age and maximum value of all boys, not the data of a particular boy.

分组查询前,可以通过关键字【where】先把满足条件的人分出来,再分组。

select 分组列,聚合函数1... from 表名 where 条件 group by 分组列;
select c_id,avg(score) from scores where c_id in (1,2,3) group by c_id;

分组查询后,也可以通过关键字【having】把组信息中满足条件的组再细分出来。

select 分组列,聚合函数1... from 表名 where 条件 group by 分组列 having 聚合函数或列名(条件);
select gender,avg(age),sum(age) sum_age from student GROUP BY gender HAVING sum_age > 50;

面试题:where和having的区别?

  1. where是写在group by之前的筛选,在分组前筛选;having是写在group by之后,分组后再筛选。
  2. where只能使用分组的列作为筛选条件;having既可以使用分组的列,也可以使用聚合函数列作为筛选条件。

limit字句,用来限定查询结果的起始行,以及总行数。

limit是 mysql 独有的语法。

select * from student limit 4,3;
select * from student limit 4;
  • 如果只有一个参数,则表示从起始位置查找4条记录。
    [En]

    if there is only one parameter, it means to find 4 records from the starting position.*

  • 如果两个参数,说明从第4行下一行,向后查找3条记录。

面试题:

  • MySQL:limit
  • Oracle:rownum
  • SqlServer:top

分析:
student表中有10条数据,如果每页显示4条,分几页?3页
3页怎么来的?(int)(Math.ceil(10 / 4));
显示第一页的数据:select * from student limit 0,4;
第二页:select * from student limit 4,4;
第三页:select * from student limit 8,4;

一个问题:我想要判断在student表中有没有叫”小红”的这个人?

1.0版本

select * from student where name = '小红';
select id from student where name = '小红';

2.0版本

select count(id) from student where name = '小红';

3.0版本

select id from student where name = '小红' limit 1;

注意:Limit子句永远是在整个的sql语句的最后。

多表查询

select * from student,teacher;

如果这两个表没有任何关联,我们将不会连接这两个表。

[En]

If the two tables do not have any association, we will not join the two tables.

在一个 select * from 表名1,表名2;,就会出现笛卡尔乘积,会生成一张虚拟表,这张虚拟表的数据就是表1和表2两张表数据的乘积。

注意:开发中,一定要避免出现笛卡尔积。

多表连接的方式有四种:

  • 内连接
  • 外连接**
  • 全连接
  • 子查询

1992年的语法。

-- 查询学号,姓名,年龄,分数,通过多表连接查询,student和scores通过id和s_id连接
SELECT
    stu.id 学号,
    stu.name 姓名,
    stu.age 年龄,
    sc.score 分数
FROM
    student stu,
    scores sc
WHERE
    stu.id = sc.s_id;
-- 查询学号,姓名,年龄,分数,科目名称,通过多表查询,student和scores,course
SELECT
    stu.id 学号,
    stu.name 姓名,
    stu.age 年龄,
    sc.score 分数,
    c.name 科目
FROM
    student stu,
    scores sc,
    course c
WHERE
    stu.id = sc.s_id
AND
    c.id = sc.c_id;
-- 查询学号,姓名,年龄,分数,科目名称,老师名称,通过多表查询,student和scores,course,teacher
SELECT
    stu.id 学号,
    stu.name 姓名,
    stu.age 年龄,
    sc.score 分数,
    c.name 科目,
    t.name 老师
FROM
    student stu,
    scores sc,
    course c,
    teacher t
WHERE
    stu.id = sc.s_id
AND
    c.id = sc.c_id
AND
    c.t_id = t.id;
-- 查询老师的信息以及对应教的课程
SELECT
    t.id 教师号,
    t.NAME 教师姓名,
    c.NAME 科目名
FROM
    teacher t,
    course c
WHERE
    t.id = c.t_id;

SQL92语法,多表查询,如果有数据为null,会过滤掉。

-- 查询学号,姓名,年龄,分数,科目名称,通过多表查询,student和scores,course
-- 在查询的基础上,进一步筛选,筛选小红和张小军的成绩
SELECT
    stu.id 学号,
    stu.name 姓名,
    stu.age 年龄,
    sc.score 分数,
    c.name 科目
FROM
    student stu,
    scores sc,
    course c
WHERE
    stu.id = sc.s_id
AND
    c.id = sc.c_id
AND
    stu.name in ('小红','张小军');
-- 查询学号,姓名,年龄,分数,科目名称,通过多表查询,student和scores,course
-- 在查询的基础上,进一步筛选,筛选小红和张小军的成绩
-- 在小红和张小军成绩的基础上进一步再筛选,筛选他们的java成绩
SELECT
    stu.id 学号,
    stu.name 姓名,
    stu.age 年龄,
    sc.score 分数,
    c.name 科目
FROM
    student stu,
    scores sc,
    course c
WHERE
    stu.id = sc.s_id
AND
    c.id = sc.c_id
AND
    stu.name in ('小红','张小军')
AND
    c.name = 'java';
-- 查询学号,姓名,年龄,分数,科目名称,通过多表查询,student和scores,course
-- 找出最低分和最高分,按照科目分组,每一科
SELECT
    sc.c_id,
    max( score ),
    min( score ),
    c.name
FROM
    scores sc,
    course c
WHERE
    sc.c_id = c.id
GROUP BY
    sc.c_id;

1999年的语法。

在我们刚才的sql当中,使用逗号分隔两张表进行查询,mysql进行优化默认就等效于内连接。

使用【join】关键字,使用【on】来确定连接条件。【where】只做筛选条件。

SELECT
    t.*,
    c.* ,
    sc.*
FROM
    teacher t
    INNER JOIN course c ON c.t_id = t.id
    INNER JOIN scores sc ON sc.c_id = c.id;

内连接和外连接的区别:

  • 对于[NER JOIN]的两个表,如果[Driven TABLE]在[Driven TABLE]中找不到匹配的记录,则最终记录将不会出现在结果集中。
    [En]

    for the two tables of [inner join], if the [driven table] cannot find a matching record in the [driven table], the final record will not appear in the result set.*

  • 对于外部联接中的两个表,即使驱动表中的记录在驱动表中找不到匹配的记录,也应该将该记录添加到最终结果集中。根据[驱动器表]的位置不同,可分为[左外接]和[右外接]。
    [En]

    for the two tables in the external join, even if the record in the driven table cannot find a matching record in the driven table, the record should be added to the final result set. According to the location of different [driver table], it can be divided into [left outer connection] and [right outer connection].*

  • 对于LEFT JOIN,左侧的表占主导地位,左侧的表的记录完全出现在结果集中。
    [En]

    for left joins, the table on the left is dominant, and the record of the table on the left appears completely in the result set.*

  • 对于Right Join,右边的表占主导地位,左边的表的记录完全出现在结果集中。
    [En]

    for right join, the table on the right is dominant, and the record of the table on the left appears completely in the result set.*

外连接的关键字【outter join】,也可以省略outter,连接条件同样使用【on】关键字。

SELECT
    t.*,
    c.*
FROM
    teacher t
    LEFT JOIN course c ON t.id = c.t_id;
SELECT
    t.*,
    c.*
FROM
    course c
    RIGHT JOIN teacher t ON t.id = c.t_id;

mysql不支持全连接。oracle支持全连接。

SELECT
    *
FROM
    teacher t
    FULL JOIN course c ON c.t_id = t.id;

我们可以通过一些手段来达到完全连接的效果。

[En]

We can achieve the effect of full connection by some means.

SELECT
    t.*,
    c.*
FROM
    teacher t
    LEFT JOIN course c ON t.id = c.t_id
UNION
SELECT
    t.*,
    c.*
FROM
    teacher t
    RIGHT JOIN course c ON t.id = c.t_id
-- 1.查询'01'号学生的姓名和各科成绩 **
SELECT
    s.id sid,
    s.name sname,
    c.name cname,
    sc.score
FROM
    student s
    LEFT JOIN scores sc ON s.id = sc.s_id
    LEFT JOIN course c ON c.id = sc.c_id
WHERE
    s.id = 1;
-- 2.查询各个学科的平均成绩和最高成绩**
SELECT
    c.id,
    c.name,
    AVG( sc.score ),
    max( sc.score )
FROM
    course c
    LEFT JOIN scores sc ON c.id = sc.c_id
GROUP BY
    c.id,
    c.name;
-- 3.查询每个同学的最高成绩和科目名称****
SELECT
    t.id,
    t.NAME,
    c.id,
    c.NAME,
    r.score
FROM
    (
    SELECT
        s.id,
        s.NAME,(
        SELECT
            max( score )
        FROM
            scores r
        WHERE
            r.s_id = s.id
        ) score
    FROM
        student s
    ) t
    LEFT JOIN scores r ON r.s_id = t.id
    AND r.score = t.score
    LEFT JOIN course c ON r.c_id = c.id;
-- 4.查询所有姓张的同学的各科成绩**
SELECT
    s.id,
    s.name,
    c.name cname,
    sc.score
FROM
SELECT
    s.id,
    s.name,
    c.name cname,
    sc.score
FROM
    student s
    LEFT JOIN scores sc ON sc.s_id = s.id
    LEFT JOIN course c ON c.id = sc.c_id
WHERE
    s.name LIKE '张%';
-- 5.查询每个课程的最高分的学生信息*****
SELECT
    *
FROM
    student s
WHERE
    id IN (
    SELECT DISTINCT
        r.s_id
    FROM
        (
        SELECT
            c.id,
            c.NAME,
            max( score ) score
        FROM
            student s
            LEFT JOIN scores r ON r.s_id = s.id
            LEFT JOIN course c ON c.id = r.c_id
        GROUP BY
            c.id,
            c.NAME
        ) t
        LEFT JOIN scores r ON r.c_id = t.id
    AND t.score = r.score
    )

-- 6.查询名字中含有'张'或'李'字的学生的信息和各科成绩。
SELECT
    s.id,
    s.NAME sname,
    sc.score,
    c.NAME
FROM
    student s
    LEFT JOIN scores sc ON s.id = sc.s_id
    LEFT JOIN course c ON sc.c_id = c.id
WHERE
    s.NAME LIKE '%张%'
    OR s.NAME LIKE '%李%';
-- 7.查询平均成绩及格的同学的信息。(子查询)
SELECT
    *
FROM
    student
WHERE
    id IN (
    SELECT
        sc.s_id
    FROM
        scores sc
    GROUP BY
        sc.s_id
    HAVING
    avg( sc.score ) >= 70
    )
-- 8.将学生按照总分数进行排名。(从高到低)
SELECT
    s.id,
    s.NAME,
    sum( sc.score ) score
FROM
    student s
    LEFT JOIN scores sc ON s.id = sc.s_id
GROUP BY
    s.id,
    s.NAME
ORDER BY
    score DESC,
    s.id ASC;
-- 9.查询数学成绩的最高分、最低分、平均分。
SELECT
    c.NAME,
    max( sc.score ),
    min( sc.score ),
    avg( sc.score )
FROM
    course c
    LEFT JOIN scores sc ON c.id = sc.c_id
WHERE
    c.NAME = '数学';
-- 10.将各科目按照平均分排序。
SELECT
    c.id,
    c.NAME,
    avg( sc.score ) score
FROM
    course c
    LEFT JOIN scores sc ON c.id = sc.c_id
GROUP BY
    c.id,
    c.NAME
ORDER BY
    score DESC;

Original: https://www.cnblogs.com/YQuicksilver/p/16610933.html
Author: QuickSilver
Title: 2022-08-16 数据库查询语言之——-DQL

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/504976/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • 手写LRU缓存淘汰算法

    概述 LRU算法全称为 Least Recently Used是一种常见的页面缓存淘汰算法,当缓存空间达到达到预设空间的情况下会删除那些 最久没有被使用的数据 。 常见的页面缓存淘…

    数据库 2023年6月11日
    0118
  • navicat~导出数据库密码

    当我们mysql密码忘记了,而在navicat里有记录,我们应该如何导出这个密码呢? 第一步:文件菜单,导出链接,导出连接获取到 connections.ncx 文件 这里需要勾选…

    数据库 2023年5月24日
    0171
  • MySQL金额数字转为大写中文

    MySQL版本:5.7.34-log通过创建函数的方法,目前可以实现整数金额的转换,网上暂未找到MySQL版本的故自己参照其他数据库版本的改编了一下, 仅供参考!!!使用方法:se…

    数据库 2023年5月24日
    063
  • 关于接口设计的思考–我们真的需要这么多入参吗

    最近,我改造一个旧接口时发现,这个接口有 30 多个入参,而事实上并不需要那么多,而且,这个接口还存在比较大的安全隐患。所以,关于如何设计接口入参,我想谈谈自己的一些想法。 当然,…

    数据库 2023年6月6日
    062
  • MySQL之视图、触发器、事务、索引及其他知识补充

    一、视图 视图是将SQL语句的查询结果当做虚拟表实体化保存起来,以后可以反复使用 create view teacher2course as select * from teach…

    数据库 2023年5月24日
    077
  • Linux Centos 打开和关闭防火墙

    systemctl status firewalld.service # 查看防火墙状态 systemctl start firewalld.service # 开启防火墙 sys…

    数据库 2023年6月14日
    085
  • 正则表达式

    1.正则表达式分类 正则表达式:REGEXP,REGular EXPression。正则表达式分为两类: Basic REGEXP(基本正则表达式) Extended REGEXP…

    数据库 2023年6月15日
    081
  • 第04章 MySQL运算符详解

    第04章 MySQL运算符详解 1. 算术运算符 算术运算符主要用于数学运算,可以在运算符前后连接两个数值或表达式,并对数值或表达式执行加(+)、减(-)、乘()、除(/)和模(%…

    数据库 2023年5月24日
    087
  • leetcode 513. Find Bottom Left Tree Value 找树左下角的值 (简单)

    给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 输入: root = [2,1,3]输出: 1 示例 2…

    数据库 2023年6月16日
    077
  • pycharm2022.2.1版本设置中文语言

    进入”File👉Sttings”界面 进入”Plugins(插件)”下,输入Chinese,找到”Chinese (Si…

    数据库 2023年6月14日
    089
  • MySQL 中如何归档数据

    归档,在 MySQL 中,是一个相对高频的操作。 它通常涉及以下两个操作: [En] It usually involves the following two actions: …

    数据库 2023年5月24日
    079
  • 新版 google 谷歌浏览器跨域问题

    新版本的firefox火狐浏览器限制了 127.0.0.1 本地部署测试的时候,用火狐浏览器需要把 前端的 后台中的服务地址改成 http://localhost:8081 浏览器…

    数据库 2023年6月6日
    083
  • List集合分页处理的方法

    参考https://www.cnblogs.com/cmz-32000/p/12186362.html 解决了数组越界问题 参数页码大于总页码时返回null(可根据自己业务调整为返…

    数据库 2023年6月11日
    066
  • Java基础三—Object对象

    Object通用方法 public final native Class<?> getClass() public native int hashCode() publ…

    数据库 2023年6月6日
    076
  • JavaWeb核心篇(7)——VUE和Element

    VUE&Element 今日目标: 能够使用VUE中常用指令和插值表达式 能够使用VUE生命周期函数 mounted 能够进行简单的 Element 页面修改 能够完成查询…

    数据库 2023年6月14日
    077
  • 凤凰架构: 构建可靠的大型分布式系统

    推荐一本好书: 《凤凰架构: 构建可靠的大型分布式系统》–作者:周志明 这是一本开源书,同时也已经出版。有着纸质书、电子书、开源网站文档和Github文档。文末已附上链…

    数据库 2023年6月6日
    093
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球