DQL语句
DQL( Data Query Language 数据查询语言 )
- 查询数据库数据 , 如SELECT语句
- 简单的单表查询或多表的复杂查询和嵌套查询
- 是数据库语言中最核心,最重要的语句
- 使用频率最高的语句
SELECT语法
SELECT [ALL | DISTINCT]{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}FROM table_name [as table_alias][left | right | inner join table_name2] -- 联合查询[WHERE ...] -- 指定结果需满足的条件[GROUP BY ...] -- 指定结果按照哪几个字段来分组[HAVING] -- 过滤分组的记录必须满足的次要条件[ORDER BY ...] -- 指定查询记录按一个或多个条件排序[LIMIT {[offset,]row_count | row_countOFFSET offset}];-- 指定查询的记录从哪条至哪条
注意 : [ ] 括号代表可选的 , { }括号代表必选得
指定查询字段
-- 查询表中所有的数据列结果 , 采用 **" \* "** 符号; 但是效率低,不推荐 .-- 查询所有学生信息SELECT * FROM student;-- 查询指定列(学号 , 姓名)SELECT studentno,studentname FROM student;
AS 子句作为别名
作用:
- 可给数据列取一个新别名
- 可给表取一个新别名
- 可把经计算或总结的结果用另一个新名称来代替
```sql — 这里是为列取别名(当然as关键词可以省略) SELECT studentno AS 学号,studentname AS 姓名 FROM student;
— 使用as也可以为表取别名 SELECT studentno AS 学号,studentname AS 姓名 FROM student AS s;
— 使用as,为查询结果取一个新名字 — CONCAT()函数拼接字符串 SELECT CONCAT(‘姓名:’,studentname) AS 新姓名 FROM student;
DISTINCT关键字的使用作用 : 去掉SELECT查询返回的记录结果中重复的记录 ( 返回所有列的值都相同 ) , 只返回一条```sql-- # 查看哪些同学参加了考试(学号) 去除重复项SELECT * FROM result; -- 查看考试成绩SELECT studentno FROM result; -- 查看哪些同学参加了考试SELECT DISTINCT studentno FROM result; -- 了解:DISTINCT 去除重复项 , (默认是ALL)
where条件语句
作用:用于检索数据表中 符合条件 的记录
搜索条件可由一个或多个逻辑表达式组成 , 结果一般为真或假.
逻辑操作符
| 操作符名称 | 语法 | |
|---|---|---|
| and 或 && | a and b 或 a && b | |
| or 或 | | | a or b 或 a b | |
| not 或! | not a 或者 !a |
测试
-- 满足条件的查询(where)SELECT Studentno,StudentResult FROM result;-- 查询考试成绩在95-100之间的SELECT Studentno,StudentResultFROM resultWHERE StudentResult>=95 AND StudentResult<=100;-- AND也可以写成 &&SELECT Studentno,StudentResultFROM resultWHERE StudentResult>=95 && StudentResult<=100;-- 模糊查询(对应的词:精确查询)SELECT Studentno,StudentResultFROM resultWHERE StudentResult BETWEEN 95 AND 100;-- 除了1000号同学,要其他同学的成绩SELECT studentno,studentresultFROM resultWHERE studentno!=1000;-- 使用NOTSELECT studentno,studentresultFROM resultWHERE NOT studentno=1000;
模糊查询 :比较操作符
| 操作符名称 | 语法 | |
|---|---|---|
| is null | 字段 is null | |
| is not null | 字段 is not null | |
| bewten | where 字段 betwen xx and xx | |
| like | where 字段 like% | |
| in | where 字段 in(x,xx) |
注意:
- 数值数据类型的记录之间才能进行算术运算 ;
- 相同数据类型的数据之间才能进行比较 ;
测试:
-- 模糊查询 between and \ like \ in \ null-- =============================================-- LIKE-- =============================================-- 查询姓刘的同学的学号及姓名-- like结合使用的通配符 : % (代表0到任意个字符) _ (一个字符)SELECT studentno,studentname FROM studentWHERE studentname LIKE '刘%';-- 查询姓刘的同学,后面只有一个字的SELECT studentno,studentname FROM studentWHERE studentname LIKE '刘_';-- 查询姓刘的同学,后面只有两个字的SELECT studentno,studentname FROM studentWHERE studentname LIKE '刘__';-- 查询姓名中含有 嘉 字的SELECT studentno,studentname FROM studentWHERE studentname LIKE '%嘉%';-- 查询姓名中含有特殊字符的需要使用转义符号 '\'-- 自定义转义符关键字: ESCAPE ':'-- =============================================-- IN-- =============================================-- 查询学号为1000,1001,1002的学生姓名SELECT studentno,studentname FROM studentWHERE studentno IN (1000,1001,1002);-- 查询地址在北京,南京,河南洛阳的学生SELECT studentno,studentname,address FROM studentWHERE address IN ('北京','南京','河南洛阳');-- =============================================-- NULL 空-- =============================================-- 查询出生日期没有填写的同学-- 不能直接写=NULL , 这是代表错误的 , 用 is nullSELECT studentname FROM studentWHERE BornDate IS NULL;-- 查询出生日期填写的同学SELECT studentname FROM studentWHERE BornDate IS NOT NULL;-- 查询没有写家庭住址的同学(空字符串不等于null)SELECT studentname FROM studentWHERE Address='' OR Address IS NULL;
连接查询
JOIN 对比
| 操作符名称 | 描述 | |
|---|---|---|
| inner join | 取两个表的交集 | |
| left join | 即使右表没有匹配数据,也返回左边的行 | |
| right join | 即使左表没有匹配数据,也返回右边的行 |
七种关联查询
案例
以一个简易问答系统为例,包括问题表和问题所属标签
问题表如下:
CREATE TABLE `t_qa` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`title` varchar(200) NOT NULL DEFAULT '' COMMENT '标题',`answer_count` int(5) unsigned NOT NULL DEFAULT '0' COMMENT '回答个数',`label_id` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '标签id',`create_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建人',`create_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',`update_by` bigint(20) unsigned DEFAULT NULL COMMENT '更新人',`update_date` datetime DEFAULT NULL COMMENT '更新时间',`del_flag` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0:不删除,1:删除',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `t_qa` (`id`, `title`, `answer_count`, `label_id`, `create_by`, `create_date`, `update_by`, `update_date`, `del_flag`)VALUES(1, 'Java是什么?', 5, 1, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(2, 'PHP是什么?', 4, 2, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(3, '前端是什么?', 3, 3, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(4, 'nodejs是什么?', 2, 0, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(5, 'css是什么?', 1, 0, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(6, 'JavaScript是什么?', 0, 0, 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0);
标签表如下:
CREATE TABLE `t_label` (`id` bigint(20) NOT NULL AUTO_INCREMENT,`name` varchar(50) NOT NULL DEFAULT '' COMMENT '名称',`create_by` bigint(20) unsigned NOT NULL DEFAULT '0' COMMENT '创建人',`create_date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT '创建时间',`update_by` bigint(20) unsigned DEFAULT NULL COMMENT '更新人',`update_date` datetime DEFAULT NULL COMMENT '更新时间',`del_flag` tinyint(1) unsigned NOT NULL DEFAULT '0' COMMENT '0:不删除,1:删除',PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;INSERT INTO `t_label` (`id`, `name`, `create_by`, `create_date`, `update_by`, `update_date`, `del_flag`)VALUES(1, 'java', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(2, 'php', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(3, '大前端', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(4, 'mybatis', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(5, 'python', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0),(6, '多线程', 0, '2017-08-24 17:43:53', 0, '2017-08-24 17:43:53', 0);
一、左连接(LEFT JOIN)

查询结果:
| 问题 | 回答个数 | 标签id | 标签名称 |
|---|---|---|---|
| Java是什么? | 5 | 1 | java |
| PHP是什么? | 4 | 2 | php |
| 前端是什么? | 3 | 3 | 大前端 |
| nodejs是什么? | 2 | NULL | NULL |
| css是什么? | 1 | NULL | NULL |
| JavaScript是什么? | 1 | NULL | NULL |
sql:
SELECTtq.title, tq.answer_count, tl.id, tl.nameFROMt_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.id
二、右连接(RIGHT JOIN)

查询结果:
| 问题 | 回答个数 | 标签id | 标签名称 |
|---|---|---|---|
| Java是什么? | 5 | 1 | java |
| PHP是什么? | 4 | 2 | php |
| 前端是什么? | 3 | 3 | 大前端 |
| NULL | NULL | 4 | mybatis |
| NULL | NULL | 5 | python |
| NULL | NULL | 6 | 多线程 |
sql:
SELECTtq.title, tq.answer_count, tl.id, tl.nameFROMt_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.id
三、内连接(INNER JOIN)

查询结果:
| 问题 | 回答个数 | 标签id | 标签名称 |
|---|---|---|---|
| Java是什么? | 5 | 1 | java |
| PHP是什么? | 4 | 2 | php |
| 前端是什么? | 3 | 3 | 大前端 |
sql语句:
SELECTtq.title, tq.answer_count, tl.id, tl.nameFROMt_qa tq INNER JOIN t_label tl ON tq.label_id = tl.id
四、左独有连接(LEFT JOIN)

查询结果:
| 问题 | 回答个数 | 标签id | 标签名称 |
|---|---|---|---|
| nodejs是什么? | 2 | NULL | NULL |
| css是什么? | 1 | NULL | NULL |
| JavaScript是什么? | 0 | NULL | NULL |
SELECTtq.title, tq.answer_count, tl.id, tl.nameFROMt_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.idWHEREtl.id IS NULL
五、右独有连接(RIGHT JOIN)

查询结果:
| 问题 | 回答个数 | 标签id | 标签名称 |
|---|---|---|---|
| NULL | NULL | 4 | mybatis |
| NULL | NULL | 5 | python |
| NULL | NULL | 6 | 多线程 |
sql:
SELECTtq.title, tq.answer_count, tl.id, tl.nameFROMt_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.idWHEREtq.label_id IS NULL
六、全连接(FULL JOIN)

由于MySQL不支持FULL OUTER JOIN,所以如果有全连接需求时,可用表达式:full outer join = left outer join UNION right outer join来实现。
UNION 和 UNION ALL 操作符
UNION 操作符用于合并两个或多个 SELECT 语句的结果集。
请注意:UNION 内部的 SELECT 语句必须拥有相同数量的列。列也必须拥有相似的数据类型。同时,每条 SELECT 语句中的列的顺序必须相同。
SQL UNION 语法
SELECT column_name(s) FROM table_name1UNIONSELECT column_name(s) FROM table_name2
注释:默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。
SQL UNION ALL 语法
SELECT column_name(s) FROM table_name1UNION ALLSELECT column_name(s) FROM table_name2
另外,UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。
| 问题 | 回答个数 | 标签id | 标签名称 |
|---|---|---|---|
| Java是什么? | 5 | 1 | java |
| PHP是什么? | 4 | 2 | php |
| 前端是什么? | 3 | 3 | 大前端 |
| nodejs是什么? | 2 | NULL | NULL |
| css是什么? | 1 | NULL | NULL |
| JavaScript是什么? | 0 | NULL | NULL |
| NULL | NULL | 4 | mybatis |
| NULL | NULL | 5 | python |
| NULL | NULL | 6 | 多线程 |
sql:
SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.idUNIONSELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.id
七、全连接去交集(FULL JOIN)

结果
| 问题 | 回答个数 | 标签id | 标签名称 |
|---|---|---|---|
| nodejs是什么? | 2 | NULL | NULL |
| css是什么? | 1 | NULL | NULL |
| JavaScript是什么? | 0 | NULL | NULL |
| NULL | NULL | 4 | mybatis |
| NULL | NULL | 5 | python |
| NULL | NULL | 6 | 多线程 |
SQL:
SELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq LEFT JOIN t_label tl ON tq.label_id = tl.id WHERE tl.id IS NULLUNIONSELECT tq.title, tq.answer_count, tl.id, tl.name FROM t_qa tq RIGHT JOIN t_label tl ON tq.label_id = tl.id WHERE tq.label_id IS NULL
排序和分页
排序
语法 : ORDER BY
ORDER BY 语句用于根据指定的列对结果集进行排序。ORDER BY 语句默认按照ASC升序对记录进行排序。如果您希望按照降序对记录进行排序,可以使用 DESC 关键字。
— 查询 数据库结构-1 的所有考试结果(学号 学生姓名 科目名称 成绩)
-- 按成绩降序排序SELECT s.studentno,studentname,subjectname,StudentResultFROM student sINNER JOIN result rON r.studentno = s.studentnoINNER JOIN `subject` subON r.subjectno = sub.subjectnoWHERE subjectname='数据库结构-1'ORDER BY StudentResult DESC
分页
语法 :
好处 : (用户体验,网络传输,查询压力)
SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset
推导:
第一页 : limit 0,5
第二页 : limit 5,5
第三页 : limit 10,5
……
第N页 : limit (pageNo-1)*pageSzie,pageSzie
[pageNo:页码, pageSize:单页面显示条数
— 每页显示5条数据
SELECT s.studentno,studentname,subjectname,StudentResultFROM student sINNER JOIN result rON r.studentno = s.studentnoINNER JOIN `subject` subON r.subjectno = sub.subjectnoWHERE subjectname='数据库结构-1'ORDER BY StudentResult DESC , studentnoLIMIT 0,5
— 查询 JAVA第一学年 课程成绩前10名并且分数大于80的学生信息(学号,姓名,课程名,分数)
SELECT s.studentno,studentname,subjectname,StudentResultFROM student sINNER JOIN result rON r.studentno = s.studentnoINNER JOIN `subject` subON r.subjectno = sub.subjectnoWHERE subjectname='JAVA第一学年'ORDER BY StudentResult DESCLIMIT 0,10
子查询
什么是子查询?
在查询语句中的WHERE条件子句中,又嵌套了另一个查询语句 嵌套查询可由多个子查询组成,求解的方式是由里及外; 子查询返回的结果一般都是集合,故而建议使用IN关键字;
有三张表分别如下:
- customers: 存储顾客信息 | cust_id | cust_name | cust_city | cust_country | csut_email | | —- | —- | —- | —- | —- | | 1001 | test01 | 广州 | 中国 | 11@qq.com | | 1002 | test02 | 深圳 | 中国 | 21@qq.com | | 1003 | test03 | 上海 | 中国 | 23@qq.com | | 1004 | test04 | 北京 | 中国 | 25@qq.com | | 1005 | test05 | 长沙 | 中国 | 26@qq.com | | 1006 | test06 | 纽约 | 美国 | 123@163.com |
2. orderitems:只存储订单信息,无客户信息
| order_num | prod_id | quantity | item_price | |
|---|---|---|---|---|
| 201901 | TNT1 | 1 | 1000 | |
| 201902 | TNT2 | 2 | 2000 | |
| 201903 | TNT3 | 3 | 3000 |
3.orders:存储订单号和顾客id
| order_num | cust_id | ||
|---|---|---|---|
| 201901 | 1001 | ||
| 201902 | 1002 | ||
| 201903 | 1003 |
注意:一般在子查询中,程序先运行在嵌套在最内层的语句,再运行外层。因此在写子查询语句时,可以先测试下内层的子查询语句是否输出了想要的内容,再一层层往外测试,增加子查询正确率。否则多层的嵌套使语句可读性很低。
子查询训练
训练1:
查询买了商品为’TNT2’的顾客信息
子查询中涉及3张表的订单。因此分三步,1. 在orderitems里找出TNT2的订单号;2. 在orders里找出第一步找出的订单号对应的客户id;3. 在customers中找出第二步对应客户的所有信息。
-- 1. 在orderitems里找出TNT2的订单号SELECT order_num FROM orderitems WHERE prod_id='TNT2';-- 2. 在orders里找出第一步找出的订单号对应的客户idSELECT cust_id FROM ordersWHERE order_numIN (SELECT order_num FROM orderitems WHERE prod_id='TNT2');--3. 在customers中找出第二步对应客户的所有信息SELECT * FROM customersWHERE cust_idIN (SELECT cust_id FROM orders WHERE order_num IN(SELECT order_num FROM orderitems WHERE prod_id='TNT2'));
子查询一般与IN操作符结合使用,也可用=><等。
子查询还可以用于计算字段。
如,想要查询每个客户的订单数
分步思考:1. 查询某个客户的订单数;2. 某个客户改为所有客户。
