文章目录
说明
本文基于【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源码,这可是大神进阶的必由之路啊!
先说这么多吧,有感而发~
写了这么久,希望得到大家的支持!谢谢!