#数据库--第2章 数据库查询
这一章节将会介绍所有的数据库查询方法,使用的数据是 上一章 介绍和导入的数据。
一、基础查询
1、投影操作
1.1 选取属性列
-- 查询 orders 表中所有 O_CLERK 字段的值
select O_CLERK from orders;
关键字 distinct 表示取消重复行
select distinct O_CLERK from orders;
给 O_CLERK 起别名为 clerk
select distinct O_CLERK clerk from orders;
1.2 算数表达式
select distinct O_TOTALPRICE, O_TOTALPRICE / 100 new_O_TOTALPRICE from orders;
1.3 函数
select distinct O_TOTALPRICE, round(O_TOTALPRICE) round_O_TOTALPRICE from orders;
1.4 常量
注意:常量既可以是字符常量,也可以是数值常量
select 'used', O_TOTALPRICE, 'dollar', 1 from orders;
2、条件查询
2.1 比较大小
注意:不等于有两种表示方法: !=、<>
select O_TOTALPRICE from orders where O_TOTALPRICE > 300000;
2.2 范围查询
关键字为:[not] between…and…
select O_TOTALPRICE from orders where O_TOTALPRICE between 200000 and 300000;
select O_TOTALPRICE from orders where O_TOTALPRICE not between 200000 and 300000;
2.3 确定集合
关键字为:[not] in (…)
注意:一个查询结果表可以视为一个集合
select distinct O_ORDERDATE, O_ORDERSTATUS from orders where O_ORDERSTATUS in ('O', 'F');
select distinct O_ORDERDATE, O_ORDERSTATUS from orders where O_ORDERSTATUS not in ('O', 'F');
2.4 字符匹配
关键字为:[not] like
% 表示任意长度的任意字符
select distinct O_CLERK from orders where O_CLERK like '%1';
_ 表示长度为 1 的任意字符
select distinct O_CLERK from orders where O_CLERK like 'Clerk#00000095_';
若想要查询的字符串含有 %、 _ ,可以使用转义字符 \
select distinct O_COMMENT from orders where O_COMMENT like '\%1';
也可以用 escape 指定转义字符
select distinct O_COMMENT from orders where O_COMMENT like '*%1' escape '*';
2.5 涉及空值 NULL 的查询
关键字:is [not] null
select distinct O_CLERK from orders where O_COMMENT is null;
select distinct O_CLERK from orders where O_COMMENT is not null;
2.6 多重条件查询
关键字:and、or
select distinct * from orders where O_TOTALPRICE between 299900 and 300000 and O_ORDERSTATUS in ('O');
select distinct * from orders where O_TOTALPRICE between 299900 and 300000 or O_ORDERSTATUS in ('O');
3、排序
关键字 order by … [asc|desc]
asc 即 ascend 升序
select distinct O_ORDERDATE, O_TOTALPRICE from orders order by O_ORDERDATE asc;
desc 即 descend 降序
select distinct O_ORDERDATE, O_TOTALPRICE from orders order by O_ORDERDATE desc;
4、函数
SQL 函数分为两大类:1、聚集函数(Aggregate Function) 2、标量函数(Scalar Function)
聚集函数:多个输入,一个输出
常用的有:
SUM() - 返回总和
AVG() - 返回平均值
COUNT() - 返回行数
MAX() - 返回最大值
MIN() - 返回最小值
FIRST() - 返回第一个记录的值
LAST() - 返回最后一个记录的值
标量函数:多个输入,多个输出,例如:
常用的有:
UCASE() - 将某个字段转换为大写
LCASE() - 将某个字段转换为小写
MID() - 从某个文本字段提取字符,MySql 中使用
SubString(字段,1,end) - 从某个文本字段提取字符
LEN() - 返回某个文本字段的长度
ROUND() - 对某个数值字段进行指定小数位数的四舍五入
NOW() - 返回当前的系统日期和时间
FORMAT() - 格式化某个字段的显示方式
5、分组
关键字:group by … [having aggregate_function()]
group by 的执行过程为:
1、从 from 指定的表中执行 where 得到结果
2、之后再用 group by 指定的字段进行分组
3、对于每一组,再执行 having 语句,得到筛选后的分组
4、对于每一组,再执行 select 语句,若存在多个值,则只返回第一个值
注意:如果有某一组有多个值,则只给出第一个值
select O_TOTALPRICE, O_ORDERSTATUS from orders group by O_ORDERSTATUS;
注意:进行分组后 select 语句里的函数将会分别作用于每一组
select count(O_TOTALPRICE), O_ORDERSTATUS from orders group by O_ORDERSTATUS;
having 关键字也是进行条件筛选
SQL 中增加 having 子句原因是,where 关键字无法与聚合函数一起使用
如果有 group by 子句,那么 having 将会作用于每个组,否则作用和 where 一样
select count(O_TOTALPRICE), O_ORDERSTATUS from orders group by O_ORDERSTATUS having count(O_ORDERSTATUS) > 5000;
select O_TOTALPRICE, O_ORDERSTATUS from orders having O_ORDERSTATUS in ('O', 'F');
6、总结
1、select 可以接 字段名、函数、算术表达式、常量。
2、查询条件可以是:逻辑运算、范围比较、集合判断、字符匹配(注意特殊字符:%、_、\)及其所有逻辑组合
3、可以用 distinct 来去除重复行,用 order by … [asc|desc] 来对结果进行排序,用 group by [having] 对结果进行分组处理(若某组结果有多个值,select 后只返回第一个值)
4、函数分为聚集函数(Aggregate Function) 和标量函数(Scalar Function),并记住常用函数。
5、查询条件关键字有 having 和 where,having 在 group by 之后执行,可以搭配聚合函数使用,where 在 group by 之前执行,只能搭配标量函数使用
二、连接查询
注意:无论是普通连接还是外连接,若一个表的一个元组与另一个表的多个元组满足连接条件,则会将这个表的此元组会重复地与另一个表的元组进行连接。
1、普通连接
普通连接又称为内连接,即通过 where 条件将多个表进行连接,表既可以是不同的表,也可以是同一张表
select * from nation, region where nation.N_REGIONKEY = region.R_REGIONKEY;
若字段名称可区分,前面的表名可省略
select * from nation, region where N_REGIONKEY = R_REGIONKEY;
若为同一个表进行连接,则应给表起别名加以区分
select distinct A.L_ORDERKEY from lineitem A, lineitem B where A.L_COMMITDATE = B.L_SHIPDATE;
2、外连接
外连接包括左外连接、右外连接、全外连接
2.1 左外连接
关键字为:… left [outer] join … on …
左外连接即,对于左表的每一个元组在右表寻找所有满足连接条件的元组,进行连接。若没有满足条件的,则右表置为 NULL 进行连接
select * from nation left outer join region on N_REGIONKEY = R_REGIONKEY;
2.2 右外连接
关键字为 … right [outer] join … on …
右外连接即,对于右表的每一个元组在左表寻找所有满足连接条件的元组,进行连接。若没有满足条件的,则左表置为 NULL 进行连接
select * from nation right outer join region on N_REGIONKEY = R_REGIONKEY;
2.3 全外连接
关键字为:… full join … on …
全外连接即左外连接和右外连接的综合
select * from nation full join region on N_REGIONKEY = R_REGIONKEY;
三、嵌套查询
嵌套查询即,将一个完整的查询语句作为另一个查询语句的 where 或 having 子句
注意:嵌套的子句不能使用 order by
3.1-3.3 都属于不相关子查询,即查询子句和外层查询语句无关联
不相关子查询执行过程为:由里及外,逐层查询
3.4 属于相关子查询,即查询子句依赖于外层查询语句
相关子查询的执行过程为:依次选取外层查询的每一行记录,放入子查询里进行查询
1、带 in 谓词的嵌套查询
注意:如果子句结果不唯一只能用 in ,若结果唯一则 = 、in 都可以
-- 查询在 orders 里订单状态为 O、F 的顾客出现次数大于二十的姓名和地址
select C_NAME, C_ADDRESS from customer where C_CUSTKEY in
(select O_CUSTKEY from orders where O_ORDERSTATUS in ('O', 'F') group by O_CUSTKEY having count(O_CUSTKEY) > 20);
2、带比较运算符的嵌套查询
注意:只有当子句结果唯一是才能用才能用比较运算符
-- 查询账户金额小于订单号为 279812 的订单金额的客户
select * from customer where C_ACCTBAL < (select O_TOTALPRICE from orders where O_ORDERKEY = 279812);
3、带 any、all 谓词的子查询
注意:需要搭配使用比较运算符
>any: 大于子查询结果中的某个值
>all: 大于子查询结果中的所有值
<any: 小于子查询结果中的某个值
<all: 小于子查询结果中的所有值
>=any: 大于等于子查询结果中的某个值
>=all: 大于等于子查询结果中的所有值
<=any: 小于等于子查询结果中的某个值
<=all: 小于等于子查询结果中的所有值
= any: 等于子查询结果中的某个值
=all: 等于子查询结果中的所有值(通常没有实际意义)
!=(或<>)any: 不等于子查询结果中的某个值
!=(或<>)all: 不等于子查询结果中的任何一个值
-- 查询账户金额小于 9116 号顾客下的订单的金额的账户
select * from customer where C_ACCTBAL <all (select O_TOTALPRICE from orders where O_CUSTKEY = 9116);
4、带 [not] exists 谓词的子查询
注意:[not] exists 只是用来判断子查询是否为空,exists 若子查询结果为空返回 true,否则返回 false,not exists 相反。
-- 查询所有订单日期为 1996-01-02 的客户姓名
select C_NAME from customer where exists (select * from orders where O_CUSTKEY=C_CUSTKEY and O_ORDERDATE='1996-01-02');
5、总结
1、所有带 in、any、all、比较运算符的子查询都能用 exists 等价替换,反之则不一定
2、从执行过程不难看出,相关子查询速度会比不相关子查询要慢,所以写嵌套查询的时候应尽量避免相关子查询语句
四、集合查询
一次查询结果可以视为一个集合,自然就会有集合操作:交、并、差
要求进行集合操作的两个表的列数一样且每列的数据类型对应相同
1、并
关键字:union [all]
注意:union 会自动去掉重复行, union all 则保留重复行
-- 查询订单金额大于 500000 或者 订单日期在 1993-1-1 之前的订单
select * from orders where O_TOTALPRICE > 500000 union select * from orders where O_ORDERDATE < '1993-1-1';
2、交
关键字:intersect
注意:mysql 不支持集合交操作
-- 查询订单金额大于 500000 且 订单日期在 1993-1-1 之前的订单
select * from orders where O_TOTALPRICE > 500000 intersect select * from orders where O_ORDERDATE < '1993-1-1';
3、差
关键字:except
注意:mysql 不支持集合差操作
-- 查询订单金额大于 500000 且 订单日期不在 1993-1-1 之前的订单
select * from orders where O_TOTALPRICE > 500000 except select * from orders where O_ORDERDATE < '1993-1-1';
五、最后总结
sql 语句的执行顺序为:from -> join -> on -> where -> group by -> function -> having -> select -> distinct -> order by