检索信息
SELECT语句允许以你喜欢的方式检索和显示数据表里的信息。通常SELECT语句由以下几个部分组成:
SELECT what to retrieve
FORM table or tables
WHERE conditions that data must satisfy;
在写SELECT语句时,尽量把你想检索的东西描述清楚,再把可选子句写出来。(FROM和WHERE就是比较常见的两个子句),其他子句包括GROUP BY、ORDER BY和LIMIT等。
有趣的是,SQL语句对书写格式的要求并没有Shell或大多数编程语言那么严格,所以你在书写SELECT语句时,选择换行符的位置以及大小写的要求时完全可以按照你的个人习惯来书写,但是良好的书写习惯会使SQL语句的阅读性和后期的数据库维护更便捷。
FROM子句一般不能省略(你要指定从哪个数据表检索数据),但SELECT 当操作不涉及数据表时,完全没有必要把FROM子句写出来,例如:
mysql> SECLECT 2+2, 'Hello, World!', VERSION();
MySQL允许把表达式的计算结果当做输出列的值,而不引用数据表。但是,当你明确需要使用哪个数据表检索数据时,应该用FROM子句指定数据表,当然还需要把想要查看的数据列的名字列举出来。例如:
mysql> SELECT * FROM student;
上面这条查询将把student数据表的所有数据列全部显示出来。(当然,检索时应尽量避免 * 的使用)想要查询某一列的数据时,在SELECT后把数据列的名字逐个列出来就行,多个数据列之间用逗号隔开。例如:
mysql> SELECT name, student_id FROM student;
上面提到过SQL语句对于大小写并没有严格的要求,但是需要注意的是,数据表的名字和数据库的名字可能需要区分大小写。(比如,在Linux系统上数据表和数据库的名字是严格区分大小写的)
指定检索条件
想要完成更为精确的查询,需要给SELECT语句加上一个WHERE子句来筛选你想要的数据。例如:
mysql> SELECT * FROM score WHERE score > 95;
或者匹配某一特定行的记录:
mysql> SELECT name, city FROM student WHERE student_id = '2017011111' ;
WHERE子句里的表达式允许使用算术运算符、比较运算符和逻辑运算符,你可以灵活的使用常数、数据表的数据列和函数调用进行运算。例如:
mysql> SELECT name, birth , city, score FROM student
-> WHERE birth < '1999-10-10' AND city IN('长春‘ , '吉林') ;
上面的这条查询的意思是,从student表中找出家在长春或者吉林并且出生日期早于1999年10月10日的同学,并把他们的姓名、生日、籍贯、分数列出来。在这条查询中,用IN()操 作符来查找几个值中的某一个会很方便。
NULL 值
NULl值是一个很特殊的值。它的含义是缺省(无数据或者未知数据),所以不能用它与“有数据”的值进行运算或者比较。如果需要对NULL值进行查找,就必须使用IS NULL 或IS NOT NULL 来判断。例如:在一张记录学生成绩的表中把缺考的学生找出来:
mysql> SELECT name, student_id, score FROM student_exam
-> WHERE score IS NUll;
当然使用MySQL专用的比较操作符 <=> 也能完成NULL值与NULL 值之间的比较。上面的查询可以改为:
mysql> SELECT name, student_id, score FROM student_exam
-> WHERE NOT( score <=> NULL);
需要注意的是,NULL值与0或者空字符串`` “” ``并不相等。
对查询结果进行排序
虽然数据记录在查询结果中的先后顺序通常与他们在当初被插入时的先后顺序一致。但如果数据表一旦经过增删改查等一些操作后,这些操作往往会改变数据行在服务器所返回的数据表检索结果中的先后顺序。所以,除非你能够保证从服务器返回的数据事先没有经过任何变动。否则,想让查询结果返回你希望的先后顺序显示,就必须给查询命令增加一条ORDER BY 子句。例如:
mysql> SELECT name, student_id, sex, score FROM
-> student ORDER BY score;
ORDER BY子句默认的排序方式是升序(ASC),在ORDER BY 子句中的数据列名字后面加上DESC则表示按降序排列。也可以对查询结果的多个数据列进行排序,而每一个数据列又都可以互不影响地分别按升序或降序进行排列。例如:
mysql> SELECT name, student_id, score, sex, city
-> FROM student ORDER BY score DESC, student_id ASC;
对于包含NULL的数据行,如果设定按升序排列,他们将出现在查询的开头;如果设定按降序排列,他们将出现在查询结果的末尾。
限制查询结果中的数据行个数
查询结果往往由很多数据行构成,如果你只想要其中一小部分,可以可查询命令增加一个LIMIT子句。ORDER BY 配合LIMIT 1
列出查询中的排在第一行的那条结果。当然,你也可以指定从查询结果中抽出一部分,此时必须指定两个值,第一个值给出要在查询结果的开头部分跳过的数据记录个数,第二个值则是需要返回的数据记录个数。例如:
mysql> SELECT name, student_id, score
-> FROM student ORDER BY score DESC LIMIT 10, 5;
上面这条查询返回成绩排在11到15名的同学的信息。
对输出列进行求值和命名
前面提到过MySQL允许把表达式的结果当做输出列的值,而不引用数据表。数据表里的数据列名字也可以用在表达式里,例如:
mysql> SELECT CONCAT(student_id,' ', name) as stuinfo, CONCAT(city, ',' ,state)
-> FROM student;
在上面的查询中, 我们对输出咧的格式进行了设置:把学生的学号和姓名合起来显示(以空格分隔),城市和省份也合起来输出(以逗号分隔),并且在输出结果中分别以别名显示这两列的标题。在为数据列提供别名时,关键字AS可以省略,但是如果省略它稍不留神可能会出现错误,例如:
mysql> SELECT name city FROM student;
上面的查询本意是查询学生的姓名和籍贯,但是漏了name和city数据列之间的逗号,于是city将被视为name的别名从而成为了输出列的表头。
与日期相关的问题
MySQL中常见的有关日期的操作,有下面几种:
- 按日期排序
- 查找某个日期或者某个日期范围
- 提取日期中的年、月、日等组成部分
- 计算两个日期之间的时间距离
- 用一个日期加上或减去一个时间间隔以求出另一个日期
# 1.
mysql> SELECT * FROM student WHERE date = '2018-10-10' ;
# 2.
mysql> SELECT * FROM student WHERE date >= '2018-10-01' AND date < ' 2018-10-13' ;
# 3. 日期中的年、 月、 日可以用函数 YEAR() 、 MONTH()、 DAYOFMONTH() 分别提取出来。
mysql> SELECT * FROM student WHERE MONTH(birth) = 3; # 把生日在3月的同学列出来,也可以用MONTHNAME(birth) = 'March'
#4. 生日在同一天的同学,不一定同年。(所以可以用DAYOFMONTH)
mysql> SELECT * FROM student WHERE MONTH(birth) = 3 AND DAYOFMONTH(birth) = 29;
#5.
mysql> SELECT name, city, TIMESTAMPDIFF(YEAR, birth,CURDATE()) as age FROM student
-> WHERE birth IS NOT NULL ORDER BY age DESC LIMIT 1;
模式匹配
MySQL支持模式匹配操作,这使得我们能够在没有给出精确比较值的情况下把有关的数据行检索出来,模式匹配用(LIKE和NOT LIKE 操作符),还需要你提供一个包含通配符的字符串。_
只能匹配一个字符, %
能匹配零到任意字符序列。例如:
mysql> SELECT name, city, student_id FROM student WHERE student_id LIKE '1%' ;
mysql> SELECT name, city , student_id FROM WHERE city LIKE '__';
MySQL还提供基于正则表达式和REGEXP
操作符的另一种更为灵活和强大的匹配形式。例如:
mysql> SELECT name, city , student_id, sex FROM WHERE city REGEXP '^吉’ ;
# 把籍贯以吉开头的同学的信息列出来
# 更多关于正则表达是的知识,可以参考我关于正则表达是的笔记
设置和使用SQL变量
MySQL允许自定义变量。我们可以使用查询结果来设置变量,这使我们能够方便地把一些值保存起来以供今后查询。
mysql> SELECT @score := score FROM student WHERE score = 60 ;
mysql> SELECT name, student_id , score FROM student
-> WHERE score > @score ORDER BY score DESC;
变量额命名语法是“@变量名” ,赋值语法是在SELECT语句里使用一个“@变量名:= 值” 形式的表达式。其实上面的查询可以通过一个联结或子查询语句得到,稍后我们会看到。
SET语句也能用来对变量赋值。
mysql> SET @today := CURDATE() ;
生成计数信息
MySQL最有用的功能之一是它能够依据大量未经加工的数据生成多种统计汇总信息。找出一组数据里到底有多少种不同的取值是一项比较常见的统计工作,而关键字DISTINCT恰好能让我们把在查询结果中重复出现的数据行清除掉。例如:
mysql> SELECT DISTINCT city FROM student ORDER BY city;
上面的查询把学生籍贯不加重复的列举出来。另一个比较常见的统计工作是利用COUNT() 函数来计数。COUNT(*)能把你的查询到底选取了多少数据行做一个统计。例如:
mysql> SELECT COUNT(*) FROM student WHERE score <60 ;
上面的查询返回成绩不及格的同学的人数。COUNT(*)的统计结果是被选中的数据行的总数,而COUNT(数据列名称)值则只统计全体非NULL值的个数。COUNT()可以和DISTINCT连用,用以统计有多少不同的非NULL值。例如:
mysql> SELECT COUNT(DISTINCT city) FROM student;
上面的查询可以统计出学生数据表中到底有多少不同的城市个数。COUNT()函数和WHERE子句连用,可以筛选出不同类型的个数。例如:
mysql> SELECT COUNT(*) FROM student WHERE sex = 'F';
mysql> SELECT COUNT(*) FROM student WHERE sex = 'M';
事实上上面的查询可以用更为方便的GROUP BY子句进行分类,MySQL可以只用一个查询就把某数据列里的不同值分别出现过多少次的情况统计出来。上面的例子可以做如下修改,例如:
mysql> SELECT sex, COUNT(*) AS 人数 FROM student GROUP BY sex ;
如果需要进行这种分门别类的统计,GROUP BY子句是必不可少的选择,它的作用是让MySQL知道在统计之前应该如何对有关的数据记录分类。与反复使用多个彼此近似的查询来分别统计某数据列不同取值出现次数的做法相比,把COUNT(*)函数与GROUP BY子句相结合的做法有很多有点:
- 在开始统计之前,我们不必知道将被统计的数据列不同取值出现次数到底有多少种不同的取值
- 我们只需要使用一个而不是好几个查询
- 因为只用一个查询就能把所有的结果都查出来,所以我们还能对输出进行排序
前两个优点有助于简化查询语句的书写,而第三个优点它能让我们更加灵活地显示查询结果。例如:
mysql> SELECT city, COUNT(*) AS 人数 FROM student GROUP BY city ORDER BY 人数 DESC;
上面的查询把学生表中分别来自什么城市做一个分类,统计数量后按降序排序。(来自哪个地方的学生最多) 如果你打算用ORDER BY 子句对一个计算出来的结果进行归类,可以使用输出列的别名或者它们在查询结果里的出现位置来设定(不推荐,也不属于标准SQL的一部分)。例如:
mysql> SELECT MONTH(birth) AS Month, MONTHNAME(birth) AS name, COUNT(*) AS 人数
-> FROM student GROUP BY name ORDER BY Month;
同样,COUNT()函数还能与ORDER BY 和LIMIT子句联合使用。而想要把与某个特定COUNT()值相对应的记录找出来,需要使用HAVING子句。(WHERE和HAVING,简单地可以理解为一个在分组前筛选数据[WHERE],一个在分组后筛选数据[HAVING],WHERE后面不能跟聚合函数)例如:
mysql> SELECT city, COUNT(*) AS 人数 FROM student GROUP city HAVING 人数 > 2 ORDER BY 人数 DESC;
除COUNT()以外,MySQL还有其他一些汇总函数。(MIN()、MAX()、SUM()和AVG()..) 要让MySQL对数据行分组统计结果做进一步的统计得到所谓的 “超级聚合” 值。加上WITH ROLLUP 子句即可。例如:
mysql> SELECT sex, COUNT(*) FROM student GROUP BY sex WITH ROLLUP;
上面这条查询将对两种性别的学生人数进行汇总并生成一行输出。
2017/10/13 数据库基础笔记 (三)