基于【MySQL】的【SQL核心语法】实战演练(三)

说明

本文基于【MySQL】,使用命令行,继续实战讲解【SQL】的基本语法。
第一篇文章在MySQL系统命令、数据库建库建表删库删表、增删改查基本操作的基础上,主要讲了LIMIT、LIKE、IN、BETWEEN、AS、INSERT INTO SELECT、JOIN、UNION、CONTRAINT、INDEX等内容。
第二篇文章,又继续讲解了 ALTER TABLE、AUTO INCREMENT、VIEWS、NULL、DATE等内容。
而本文会主要围绕MySQL,继续讲解以SQL函数为核心的SQL语法,这些不算很难的知识,但也比最基本的insert、delete、update、select要高级很多了。阅读之前,请务必学会基本的增删改查(可以阅读下面的“必知必会”文章)。

必知必会

《MySQL系统命令+基础查询总结》
《MySQL命令行测试基础SQL》
《基于MySQL的SQL核心语法实战演练(一)》
《基于MySQL的SQL核心语法实战演练(二)》

熟悉数据表

这篇文章只用这两张表,建议熟悉一下(其实,看过前面文章的读者一定很熟悉了吧)。

mysql> select * from stu_grade;
+----+--------+---------+------+---------+-------+
| id | name   | chinese | math | english | grade |
+----+--------+---------+------+---------+-------+
|  1 | Sam    |     120 |  145 |     145 |   410 |
|  2 | Bob    |      88 |   98 |      95 |   278 |
|  3 | Steven |     130 |  108 |     135 |   373 |
|  4 | Amy    |     120 |  120 |     120 |   360 |
|  5 | Eleven |     130 |  130 |     140 |   400 |
|  6 | Miffy  |     125 |  145 |     135 |   405 |
|  7 | Smith  |     100 |  100 |     100 |   300 |
+----+--------+---------+------+---------+-------+
7 rows in set (0.00 sec)
mysql> select * from stu_info;
+----+--------+-----+---------------------+---------------------+---------+
| id | name   | age | birthday            | email               | country |
+----+--------+-----+---------------------+---------------------+---------+
|  1 | Sam    |  21 | 1999-05-04 08:00:00 | 123456789@qq.com    | China   |
|  2 | Bob    |  35 | 1985-12-03 09:34:20 | bobbob@gmail.com    | USA     |
|  3 | Steven |  25 | 1995-03-03 06:17:30 | steven521@gmail.com | UK      |
|  4 | Amy    |  20 | 2000-01-01 13:00:00 | amy20205205@163.com | China   |
|  5 | Eleven |  19 | 2001-07-02 21:30:00 | 11more11@163.com    | China   |
|  6 | Miffy  |  20 | 2000-08-10 12:00:00 | miffy521@126.com    | Japan   |
+----+--------+-----+---------------------+---------------------+---------+
6 rows in set (0.00 sec)

EXISTS 运算符

EXISTS 运算符用于判断查询子句是否有记录,如果有一条或多条记录存在返回 True,否则返回 False。

标准SQL语法:

SELECT column_name(s)
FROM table_name
WHERE EXISTS
(SELECT column_name FROM table_name WHERE condition);

我们据此查询一下,要求是当语文成绩存在140+的学生时,执行全表查询:

mysql> select *
    -> from stu_grade
    -> where exists(
    -> select id from stu_grade
    -> where chinese>140);
Empty set (0.00 sec)

由于语文成绩没有140+的,所以查询结果为空集。

我们再查询一下,要求是当语文成绩存在100-的学生时,执行全表查询:

mysql> select *
    -> from stu_grade
    -> where exists(
    -> select id from stu_grade
    -> where chinese<100);
+----+--------+---------+------+---------+-------+
| id | name   | chinese | math | english | grade |
+----+--------+---------+------+---------+-------+
|  1 | Sam    |     120 |  145 |     145 |   410 |
|  2 | Bob    |      88 |   98 |      95 |   278 |
|  3 | Steven |     130 |  108 |     135 |   373 |
|  4 | Amy    |     120 |  120 |     120 |   360 |
|  5 | Eleven |     130 |  130 |     140 |   400 |
|  6 | Miffy  |     125 |  145 |     135 |   405 |
|  7 | Smith  |     100 |  100 |     100 |   300 |
+----+--------+---------+------+---------+-------+
7 rows in set (0.00 sec)

全部数据都被查出来了。

Aggregate Functions

重要的聚集函数:

函数 功能 MySQL是否直接支持
AVG() 返回平均值
COUNT() 返回行数
FIRST() 返回第一个记录的值 ×
LAST() 返回最后一个记录的值 ×
MAX() 返回最大值
MIN() 返回最小值
SUM() 返回总和

想给大家纠正的一个错误认识。
可能有的人会认为,我们可以指定grade属性的值是SUM(chinese, math, english),这样可太不对了。
首先,从SUM()的参数来看,应该是单参数,绝不是多参数。
当然这只是小问题,大问题是:这些聚集函数作用的是一个列而不是一行。

认识清楚了以后,想来大家对聚集函数应该有新的认识了吧。没错,聚的就是该字段,聚的就是选中的所有。

AVG()

下面的SQL语句用于测试AVG(),分别取chinese、math、english、grade的平均值。

别在意那个浮点对不上(追求高精的话要小心这里,可能是个Bug),浮点误差本就存在。

mysql> select avg(chinese) as chinese_avg, avg(math) as math_avg, avg(english) as english_avg, avg(grade) as grade_avg
    -> from stu_grade;
+-------------+----------+-------------+-----------+
| chinese_avg | math_avg | english_avg | grade_avg |
+-------------+----------+-------------+-----------+
|    116.1429 | 120.8571 |    124.2857 |  360.8571 |
+-------------+----------+-------------+-----------+
1 row in set (0.00 sec)

下面的SQL语句实现了查询所有语文分数高于平均分的学生成绩,注意是怎么写的:

mysql> select * from stu_grade
    -> where chinese>(select avg(chinese) from stu_grade);
+----+--------+---------+------+---------+-------+
| id | name   | chinese | math | english | grade |
+----+--------+---------+------+---------+-------+
|  1 | Sam    |     120 |  145 |     145 |   410 |
|  3 | Steven |     130 |  108 |     135 |   373 |
|  4 | Amy    |     120 |  120 |     120 |   360 |
|  5 | Eleven |     130 |  130 |     140 |   400 |
|  6 | Miffy  |     125 |  145 |     135 |   405 |
+----+--------+---------+------+---------+-------+
5 rows in set (0.00 sec)

我们让这个SQL语句再复杂一些吧,查询语文、英语高于平均成绩但数学低于平均成绩的学生成绩:

mysql> select * from stu_grade
    -> where chinese>(select avg(chinese) from stu_grade)
    -> and math<(select avg(math) from stu_grade)
    -> and english>(select avg(english) from stu_grade);
+----+--------+---------+------+---------+-------+
| id | name   | chinese | math | english | grade |
+----+--------+---------+------+---------+-------+
|  3 | Steven |     130 |  108 |     135 |   373 |
+----+--------+---------+------+---------+-------+
1 row in set (0.00 sec)

COUNT()

下面的SQL语句使用COUNT(*)完成了表的行计数:

mysql> select count(*) as count from stu_grade;
+-------+
| count |
+-------+
|     7 |
+-------+
1 row in set (0.00 sec)

下面的SQL语句使用COUNT()和DISTINCT统计了所有学生来自多少个国家:

mysql> select count(distinct country) as count
    -> from stu_info;
+-------+
| count |
+-------+
|     4 |
+-------+
1 row in set (0.36 sec)

FIRST()

怎么理解这个“第一个”呢?其实就是最小的。
神奇的是Oracle、SQL Server、MySQL都不支持,但也都能等价替换。

MySQL不支持这东西,但可以等价替换一下:

SELECT column_name FROM table_name
ORDER BY column_name ASC
LIMIT 1;

使用ORDER BY+LIMIT确实也能做到。

下面的SQL语句,就查询了语文成绩最低的学生成绩,相当于FIRST():

mysql> select * from stu_grade
    -> order by chinese
    -> limit 1;
+----+-------+---------+------+---------+-------+
| id | name  | chinese | math | english | grade |
+----+-------+---------+------+---------+-------+
|  2 | Bob   |      88 |   98 |      95 |   278 |
+----+-------+---------+------+---------+-------+
3 rows in set (0.00 sec)

LAST()

怎么理解这个“最后一个”呢?其实就是最大的。
神奇的是Oracle、SQL Server、MySQL都不支持,但也都能等价替换。

MySQL不支持这东西,但可以等价替换一下:

SELECT column_name FROM table_name
ORDER BY column_name DESC
LIMIT 1;

使用ORDER BY+DESC+LIMIT确实也能做到。

下面的SQL语句,就查询了总成绩最高的学生成绩,相当于LAST():

mysql> select * from stu_grade
    -> order by grade desc
    -> limit 1;
+----+--------+---------+------+---------+-------+
| id | name   | chinese | math | english | grade |
+----+--------+---------+------+---------+-------+
|  1 | Sam    |     120 |  145 |     145 |   410 |
+----+--------+---------+------+---------+-------+
3 rows in set (0.00 sec)

MAX()

没什么可说的,这种东西大家肯定都很熟悉了。

下面的SQL语句,查询了所有学生的数学最高分:

mysql> select max(math) as math_top from stu_grade;
+----------+
| math_top |
+----------+
|      145 |
+----------+
1 row in set (0.00 sec)

MIN()

没什么可说的,这种东西大家肯定都很熟悉了。

下面的SQL语句,查询了所有学生的英语最低分:

mysql> select min(english) as english_bottom from stu_grade;
+----------------+
| english_bottom |
+----------------+
|             95 |
+----------------+
1 row in set (0.00 sec)

SUM()

没什么可说的,这种东西大家肯定都很熟悉了。

下面的SQL语句,查询了所有学生总成绩之和:

mysql> select sum(grade) as grade_sum from stu_grade;
+-----------+
| grade_sum |
+-----------+
|      2526 |
+-----------+
1 row in set (0.00 sec)

创建新表

在完成前面对聚集函数的学习之后,我们可以学习GROUP BY和HAVING。
但现有的表不适合做测试,所以新建一个表:

mysql> create table stu_login (
    -> id int not null  primary key auto_increment,
    -> stu_id int not null,
    -> web_url varchar(30) not null,
    -> count int not null default 0);
Query OK, 0 rows affected (0.72 sec)

初始化数据:

mysql> insert into stu_login(stu_id, web_url, count) values
    -> ('1', 'www.baidu.com', '25'),
    -> ('2', 'www.baidu.com', '100'),
    -> ('3', 'www.csdn.net', '40'),
    -> ('4', 'www.luogu.org.cn', '33'),
    -> ('1', 'www.baidu.com', '1'),
    -> ('2', 'www.csdn.net', '9'),
    -> ('6', 'www.jslint.com', '14'),
    -> ('3', 'www.baidu.com', '3');
Query OK, 8 rows affected (0.45 sec)
Records: 8  Duplicates: 0  Warnings: 0

全表查询验证:

mysql> select * from stu_login;
+----+--------+------------------+-------+
| id | stu_id | web_url          | count |
+----+--------+------------------+-------+
|  1 |      1 | www.baidu.com    |    25 |
|  2 |      2 | www.baidu.com    |   100 |
|  3 |      3 | www.csdn.net     |    40 |
|  4 |      4 | www.luogu.org.cn |    33 |
|  5 |      1 | www.baidu.com    |     1 |
|  6 |      2 | www.csdn.net     |     9 |
|  7 |      6 | www.jslint.com   |    14 |
|  8 |      3 | www.baidu.com    |     3 |
+----+--------+------------------+-------+
8 rows in set (0.00 sec)

URL去重查看:

mysql> select distinct web_url from stu_login;
+------------------+
| web_url          |
+------------------+
| www.baidu.com    |
| www.csdn.net     |
| www.luogu.org.cn |
| www.jslint.com   |
+------------------+
4 rows in set (0.00 sec)

准备完成,继续学习吧!

GROUP BY语句

GROUP BY 语句用于结合聚合函数,根据一个或多个列对结果集进行分组。

标准SQL语法:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name; 

下面的SQL语句聚合了不同URL的访问总量,是去重后的:

mysql> select web_url, sum(count) as num
    -> from stu_login
    -> group by web_url;
+------------------+------+
| web_url          | num  |
+------------------+------+
| www.baidu.com    |  129 |
| www.csdn.net     |   49 |
| www.luogu.org.cn |   33 |
| www.jslint.com   |   14 |
+------------------+------+
4 rows in set (0.00 sec)

HAVING语句

WHERE 关键字无法与聚合函数一起使用,而我们可能需要筛选分组后的各组数据,所以需要 HAVING 语句。

标准SQL语法:

SELECT column_name, aggregate_function(column_name)
FROM table_name
WHERE column_name operator value
GROUP BY column_name
HAVING aggregate_function(column_name) operator value;

下面的语句在GROUP BY部分的样例语句的基础上加了HAVING,筛选了总访问量大于35的网页URL:

mysql> select web_url, sum(count) as num
    -> from stu_login
    -> group by web_url
    -> having sum(count)>35;
+---------------+------+
| web_url       | num  |
+---------------+------+
| www.baidu.com |  129 |
| www.csdn.net  |   49 |
+---------------+------+
2 rows in set (0.00 sec)

Scalar Functions

函数 功能 MySQL是否直接支持
UCASE() 将某个字段转换为大写
LCASE() 将某个字段转换为小写
MID() 从某个文本字段提取字符
LEN() 返回某个文本字段的长度
ROUND() 对某个数值字段进行指定小数位数的四舍五入

UCASE()

就相当于toUpperCase()。

下面的SQL语句查询了所有学生姓名的大写表示:

mysql> select ucase(name) as upper_name
    -> from stu_info;
+------------+
| upper_name |
+------------+
| SAM        |
| BOB        |
| STEVEN     |
| AMY        |
| ELEVEN     |
| MIFFY      |
+------------+
6 rows in set (0.36 sec)

LCASE()

就相当于toLowerCase()。

下面的SQL语句查询了所有学生姓名的小写表示:

mysql> select lcase(name) as upper_name
    -> from stu_info;
+------------+
| upper_name |
+------------+
| sam        |
| bob        |
| steven     |
| amy        |
| eleven     |
| miffy      |
+------------+
6 rows in set (0.34 sec)

MID()

相当于SubString(),好像是MySQL才支持的吧。

MySQL的MID()语法:

SELECT MID(column_name,start[,length]) FROM table_name;

前两个参数是必选的,最后一个可选。
注意:start参数是从1开始的,不是0!!! 这个一定要清楚!
另外,如果不加length参数的话,就默认从start开始读到末尾。

下面的语句查询了所有学生邮箱的前10位(其实没啥实际意义):

mysql> select mid(email, 1, 10) as email_cut
    -> from stu_info;
+------------+
| email_cut  |
+------------+
| 123456789@ |
| bobbob@gma |
| steven521@ |
| amy2020520 |
| 11more11@1 |
| miffy521@1 |
+------------+
6 rows in set (0.00 sec)

LEN()

就相当于length(),查查串的实际长度。

下面的SQL语句查询了所有学生的邮箱URL长度:

mysql> select length(email) as email_url_len
    -> from stu_info;
+---------------+
| email_url_len |
+---------------+
|            16 |
|            16 |
|            19 |
|            19 |
|            16 |
|            16 |
+---------------+
6 rows in set (0.00 sec)

ROUND()

四舍五入啊,默认AVG()是四位,我们这里把AVG()结果取到四舍五入两位:

mysql> select round(avg(grade), 2) as grade
    -> from stu_grade;
+--------+
| grade  |
+--------+
| 360.86 |
+--------+
1 row in set (0.01 sec)

Date Functions

如果你还不会的话,看过来呀

完美退出

mysql> \q
Bye

总结

讲了这么多,有语法,有排坑点拨,也有实战演练,不知道大家看完之后可有收获?

SQL基本的语法点,就讲到这里了。后续还会有很多精彩的内容作为补充,希望大家还能看的尽兴!
本系列共三篇文章,希望能带领刚装好MySQL的小白通过实战熟悉基于MySQL的SQL语句的使用。

大家还可以安装Navicat,一款付费软件,但可视化效果真的很好,可以便于开发和使用。
但是对于初学者,我希望大家安安静静的敲好命令行的每个字符,同时理解形式化的查询符号语言,理解B+树的索引原理,掌握事务的ACID,打好扎实的理论基础。

还可以读读MySQL源码,这可是大神进阶的必由之路啊!
先说这么多吧,有感而发~

写了这么久,希望得到大家的支持!谢谢!

The End

发布了725 篇原创文章 · 获赞 1548 · 访问量 72万+

猜你喜欢

转载自blog.csdn.net/weixin_43896318/article/details/104928553
今日推荐