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,StudentResult
FROM result
WHERE StudentResult>=95 AND StudentResult<=100;
-- AND也可以写成 &&
SELECT Studentno,StudentResult
FROM result
WHERE StudentResult>=95 && StudentResult<=100;
-- 模糊查询(对应的词:精确查询)
SELECT Studentno,StudentResult
FROM result
WHERE StudentResult BETWEEN 95 AND 100;
-- 除了1000号同学,要其他同学的成绩
SELECT studentno,studentresult
FROM result
WHERE studentno!=1000;
-- 使用NOT
SELECT studentno,studentresult
FROM result
WHERE 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 student
WHERE studentname LIKE '刘%';
-- 查询姓刘的同学,后面只有一个字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘_';
-- 查询姓刘的同学,后面只有两个字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘__';
-- 查询姓名中含有 嘉 字的
SELECT studentno,studentname FROM student
WHERE studentname LIKE '%嘉%';
-- 查询姓名中含有特殊字符的需要使用转义符号 '\'
-- 自定义转义符关键字: ESCAPE ':'
-- =============================================
-- IN
-- =============================================
-- 查询学号为1000,1001,1002的学生姓名
SELECT studentno,studentname FROM student
WHERE studentno IN (1000,1001,1002);
-- 查询地址在北京,南京,河南洛阳的学生
SELECT studentno,studentname,address FROM student
WHERE address IN ('北京','南京','河南洛阳');
-- =============================================
-- NULL 空
-- =============================================
-- 查询出生日期没有填写的同学
-- 不能直接写=NULL , 这是代表错误的 , 用 is null
SELECT studentname FROM student
WHERE BornDate IS NULL;
-- 查询出生日期填写的同学
SELECT studentname FROM student
WHERE BornDate IS NOT NULL;
-- 查询没有写家庭住址的同学(空字符串不等于null)
SELECT studentname FROM student
WHERE 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:
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
二、右连接(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:
SELECT
tq.title, tq.answer_count, tl.id, tl.name
FROM
t_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语句:
SELECT
tq.title, tq.answer_count, tl.id, tl.name
FROM
t_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 |
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 NULL
五、右独有连接(RIGHT JOIN)
查询结果:
问题 | 回答个数 | 标签id | 标签名称 |
---|---|---|---|
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 RIGHT JOIN t_label tl ON tq.label_id = tl.id
WHERE
tq.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_name1
UNION
SELECT column_name(s) FROM table_name2
注释:默认地,UNION 操作符选取不同的值。如果允许重复的值,请使用 UNION ALL。
SQL UNION ALL 语法
SELECT column_name(s) FROM table_name1
UNION ALL
SELECT 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.id
UNION
SELECT 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 NULL
UNION
SELECT 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,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE 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,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY StudentResult DESC , studentno
LIMIT 0,5
— 查询 JAVA第一学年 课程成绩前10名并且分数大于80的学生信息(学号,姓名,课程名,分数)
SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='JAVA第一学年'
ORDER BY StudentResult DESC
LIMIT 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里找出第一步找出的订单号对应的客户id
SELECT cust_id FROM orders
WHERE order_num
IN (SELECT order_num FROM orderitems WHERE prod_id='TNT2');
--3. 在customers中找出第二步对应客户的所有信息
SELECT * FROM customers
WHERE cust_id
IN (SELECT cust_id FROM orders WHERE order_num IN
(SELECT order_num FROM orderitems WHERE prod_id='TNT2'));
子查询一般与IN操作符结合使用,也可用=><等。
子查询还可以用于计算字段。
如,想要查询每个客户的订单数
分步思考:1. 查询某个客户的订单数;2. 某个客户改为所有客户。