文章目录
前言:
现在我们来看看SQL语法的用法,包括查询语句的类型、语法格式和对应的使用场景
这篇我们讲数据查询
数据查询语言是数据库最基本的应用,其语法较为复杂,包括简单查询、带条件查询、连接查询、子查询、集合运算、数据分组、排序和限制等
1. 简单查询
日常查询中 最常用的就是用过FROM子句实现的查询
语法:
SELECT [ , ... ] FROM table_reference [ , ... ]
使用方法:
SELECT项用于指定要查询的列,FROM指定要从哪个表中查询。
如果要查询所有列,可以在SELECT后面使用*号,如果只查询特定的列,可以直接在SELECT后面指定列名,列名之间用逗号(,)隔开。
例子1:
查询training表中的所有列
SELECT * FROM training;
2. 关键字 DISTINCT
从SELECT的结果集中删除所有重复的行,使结果集中的每行都是唯一的。去重复值查询
例子:
利用distinct关键字来查询员工的岗位和奖金,去除岗位和奖金相同的记录。
select distinct job, bonus from sections;
3. 查询列的选择
例子1:
从多个表中查找多个列
其中,列a、b是表t1中的列,f1、f2是表t2中的列
SELECT a, b, f1, f2 FROM t1, t2;
例子2:
查两个字段计算出来的
SELECT a+b FROM t1;
例子3:
如果某两个或某几个表正好有一些共同的列名,推荐使用表名限定列名。不限定列名可以得到查询结果,但使用完全限定的表和列名称,可以减少数据库内部的处理工作量,从而提升查询的返回性能
SELECT t1.f1, t2.f1 from t1, t2;
4. 别名
通过使用子句AS some_name,可以为表名称或列名称指定另一个标题名显示,一般创建别名是为了让列名称的可读性更强
-
语法格式:
列和表的SQL别名分别跟在相应的列名和表名后面,中间可以加或不加一个“AS”关键字。也可以用双引号的方式来表示别名。例子:
表名限定列名,查询学号sid为10的学生的数学成绩和英语成绩
select a.sid,a.score as math, b.score as english from math a,english b where a.sid = 10 and b.sid = 10;
5. 条件查询
在SELECT语句中,可以通过设置条件以达到更精确的查询。条件由表达式与操作符共同指定,且条件返回的值是TRUE,FALSE或UNKNOWN。查询条件可以应用于WHERE子句,HAVING子句。
-
比较操作符
“>, <,>=,<=, !=, <>,=”指定的比较查询条件。当查询条件中和数字比较,可以使用单引号引起,也可以不用,当和字符及日期类型的数据比较,则必须用单引号引起 -
逻辑操作符
常用的逻辑操作符有AND、OR和NOT,他们的运算结果有三个值,分别为TRUE、FALSE和NULL,其中NULL代表未知。他们运算优先级顺序为:NOT>AND>OR运算规则表
a | b | a AND b | a OR b | NOT a |
---|---|---|---|---|
TRUE | TRUE | TRUE | TRUE | FALSE |
TRUE | FALSE | FALSE | TRUE | FALSE |
TRUE | NULL | NULL | TRUE | FALSE |
FALSE | FALSE | FALSE | FALSE | TRUE |
FALSE | NULL | FALSE | NULL | TRUE |
NULL | NULL | NULL | NULL | NULL |
- 测试运算符
测试运算符指定的范围查询条件
运算符 | 描述 |
---|---|
IN/NOT IN | 元素在/不在指定的集合中。 |
EXISTS/NOT EXISTS | 存在/不存在符合条件的元素。 |
ANY/SOME | 存在一个值满足条件。SOME是ANY的同义词。 |
ALL | 全部值满足条件。 |
BETWEEN…AND… | 在两者之间,例如a BETWEEN x AND y等效于a>= x and a <= y。 |
IS NULL/IS NOT NULL | 等于/不等于NULL。 |
LIKE/NOT LIKE | 字符串模式匹配/不匹配。 |
REGEXP | 字符串与正则表达式相匹配,仅支持STRING类型。 |
REGEXP_LIKE | 字符串与正则表达式相匹配,支持STRING类型和NUMBER类型。 |
例子1:
从表bonuses_depa中查询岗位为developer,且奖金>8000的职员信息
select * from bonuses_depa where job = 'developer' and bonus > 8000;
例子2:
从表bonuses_depa中查询姓wang,且奖金在8500~9500之间的职员信息
select * from bonuses_depa where name like 'wang%' and bonus between 8500 and 9500;
补充:
通配符 %:表示任意数量的字符,包括无字符,用于like和not like语句中。
_:下划线,表示确切的一个未知字符,用于like和not like语句中。
6. join连接查询
实际应用中所需要的数据,经常会需要查询两个或两个以上的表。这种查询两个或两个以上数据表或视图的查询叫做连接查询。连接查询通常建立在存在相互关系的父子表之间。(只要在FROM子句中出现多个表时,数据库就会执行连接)
大多数连接查询包含至少一个连接条件,连接条件可以在FROM子句中也可以在WHERE子句中
举个例子: 对A(4条记录)和B(5条记录)两个表做不指定条件的连接查询时,会得到20(4×5)条记录
语法格式:
SELECT [ , ... ] FROM table_reference
[LEFT [OUTER] | RIGHT [OUTER] | FULL [OUTER] | INNER]
JOIN table_reference
[ON { predicate } [ { AND | OR } condition ] [ , ... n ]]
注:table_reference 子句中可以是普通表、视图、子查询
-
内连接
内连接的关键字为inner join,其中inner可以省略。使用内连接,连接执行顺序必然遵循语句中所写的表的顺序。例子:
查询员工ID、最高学历和考试分数。使用training和education两个相关的列(staff_id)做查询操作
SELECT e.staff_id, e.higest_degree, t.score FROM education e JOIN training t ON (e.staff_id = t.staff_id);
- 外连接
- 内连接所指定的两个数据源处于平等的地位。而外连接不同,外连接以一个数据源为基础,将另外一个数据源与之进行条件匹配。
- 内连接返回两个表中所有满足连接条件的数据记录。外连接不仅返回满足连接条件的记录,还将返回不满足连接条件的记录。
- 外连接又分为左外连接、右外连接和全外连接。
-
左外连接
又称左连接,如图所示,是指以左边的表为基础表进行查询。
根据指定连接条件关联右表,获取基础表以及和条件匹配的右表数据,未匹配条件的右表对应的字段位置填上NULL。例子:
SELECT e.staff_id, e.higest_degree, t.score FROM education e LEFT JOIN training t ON (e.staff_id = t.staff_id);
-
右外连接
又称右连接,是指以右边的表为基础表,在内连接的基础上也查询右边表中有记录,而左边的表中没有记录的数据(左边用NULL值填充)。例子:
SELECT e.staff_id, e.higest_degree, t.score FROM education e RIGHT JOIN training t ON (e.staff_id = t.staff_id);
-
全外连接
又称全连接,是指除了返回两个表中满足连接条件的记录,还会返回两个表中不满足连接条件的所有其它行(不匹配的另外一边用NULL值填充)例子:
SELECT e.staff_id, e.higest_degree, t.score FROM education e FULL JOIN training t ON (e.staff_id = t.staff_id);
-
半连接
半连接(Semi Join)是一种特殊的连接类型,在SQL中没有指定的关键字,通过在WHERE后面使用IN或EXISTS子查询实现。当IN/EXISTS右侧的多行满足子查询的条件时,主查询也只返回一行与IN/EXISTS子查询匹配的行,而不是复制左侧的行。例子:
查看参加培训的员工的教育信息。即使training表中的许多行可能与子查询匹配(即同一个staff_id下有多个职员),也只需要从表training返回一行。
SELECT staff_id, higest_degree, education_note FROM education WHERE EXISTS (SELECT * FROM training WHERE education.staff_id = training.staff_id);
-
反连接
反连接(Anti Join)是一种特殊的连接类型,在SQL中没有指定的关键字,通过在WHERE后面使用NOT IN或NOT EXISTS子查询实现。返回所有不满足条件的行。这个关系的概念跟半连接相反。例子:
SELECT staff_id, higest_degree, education_note FROM education WHERE staff_id NOT IN (SELECT staff_id FROM training);
7. 子查询
查询是指在查询、建表或插入语句的内部嵌入查询,以获得临时结果集。
子查询可以分为相关子查询和非相关子查询
子查询类型 | 描述 |
---|---|
相关子查询 | 执行查询的时候先取得外层查询的一个属性值,然后执行与此属性值相关的子查询,执行完毕后再取得外层查询的下一个值,依次再来重复执行子查询。 |
非相关子查询 | 子查询独立于外层语句(主查询),子查询的执行不需要提前取得父查询的值,只是作为父查询的查询条件。查询执行时子查询和主查询可分为两个独立的步骤,即先执行子查询,再执行主查询。 |
子查询可以出现在FROM子句、WHERE子句、以及WITH AS子句中。
例子1:
通过相关子查询,查找每个部门中高出部门平均工资的人员
SELECT s1.last_name, s1.section_id, s1.salary
FROM staffs s1
WHERE salary >(SELECT avg(salary) FROM staffs s2 WHERE s2.section_id = s1.section_id)
ORDER BY s1.section_id;
对于staffs表的每一行,父查询使用相关子查询来计算同一部门成员的平均工资。相关子查询为staffs表的每一行执行以下步骤:
确定行的section_id。
然后使用section_id来评估父查询。
如果此行中工资大于所在部门的平均工资,则返回该行。
对于staffs表的每一行,子查询都将被计算一次。
例子2:
WITH子查询:查询培训过big data课程的员工信息
WITH bigdata_staffs AS (select staff_id,exam_date from training where course_name = 'BIG DATA' )select * from bigdata_staffs;
例子3:
通过子查询建立一个和表training具有相同表结构的表
CREATE TABLE training_new AS SELECT * FROM training WHERE 1<>1;
注:<>是不等于的意思,1<>1的条件不成立,所以子查询不会返回数据
例子4:
通过子查询向表training_new表中插入training表的所有数据
INSERT training_new SELECT * FROM training;
8. 合并结果集
除子查询外,还可以使用集合运算符处理多个查询的结果集,输出最终结果
使用语法:
select_statement UNION [ALL] select_subquery
注:Union运算符:将多个查询块的结果集合并为一个结果集输出
使用方法:
• 每个查询块的查询列数目必须相同。
• 每个查询块对应的查询列必须为相同数据类型或同一数据类型组。
•关键字ALL的意思是保持所有重复数据,而没有ALL的情况下表示删除所有重复数据。
理解:
例子:
现有两个部门的员工信息,查询获得奖金超过7000的员工信息
SELECT staff_id, name, bonus FROM bonuses_depa1 WHERE bonus > 7000 UNION ALL SELECT
staff_id, name, bonus FROM bonuses_depa2 WHERE bonus > 7000 ;
9. 差异结果集
使用MINUS/ EXCEPT运算符。对查询结果集的减法,计算存在于左边查询语句的输出、而不存在于右边查询语句输出的结果
比如:A minus B C就意味着将结果集A去除结果集B和结果集C中所包含的所有记录后的结果,即在A中存在,而在B、 C中不存在的记录
语法格式:
select_statement MINUS/EXCEPT select_statement2 [ ... ]
理解:
10. 数据分组
-
GROUP BY
数据库查询中,分组是一个非常重要的应用。分组是指将数据表中的记录以某个或者某些列为标准,值相等的划分为一组。语法格式
GROUP BY { column_name } [ , ... ]
使用方法:
○ GROUP BY子句中的表达式可以包含FROM子句中表,视图的任何列,无论这些列是否出现在SELECT列表中。
○ GROUP BY子句对行进行分组,但不保证结果集的顺序。 要对分组进行排序,请使用ORDER BY子句。
○ GROUPBY后的表达式可以使用括号,如: group by (expr1, expr2),或者 group by(expr1), (expr2)。但不支持 group by (expr1, expr2), expr3 格式。
例子:
该部门按照岗位和奖金分组,查询每组员工数,结果按人数升序排序
select job, bonus, count(staff_id) sum from bonuses_depa group by(job,bonus) order by sum;
2. HAVING子句
与GROUP BY子句配合用来选择特殊的组。HAVING子句将组的一些属性与一个常数值比较,只有满足HAVING子句中条件的组才会被提取出来
语法格式:
HAVING condition [ , ... ]
例子:
查询表sections中岗位人数大于3的各岗位员工总数。
select job, count(staff_id) from bonuses_depa group by job having count(staff_id) >3;
11. 数据排序
-
ORDER BY子句
使用ORDER BY子句对查询语句返回的行根据指定的列进行排序。如果没有ORDER BY子句,则多次执行的同一查询将不一定以相同的顺序进行行的检索。
语法格式:
ORDER BY { column_name | number | expression } [ ASC | DESC ][ NULLS FIRST | NULLS LAST ] [ , ... ]
使用方式:
○ column_name | number | expression 表示 order by 后面可以跟列名、数字、表达式(跟数字:order by 1 表示 根据查询选择列中第一个字段排序。跟表达式:order by(column1+column2) 表示根据column1与column2的和的大小来排序。)
○ ORDER BY语句默认按照升序对记录进行排序。如果希望按照降序对记录进行排序,请使用DESC关键字。
○ NULLS FIRST | NULLS LAST 关键字指定ORDER BY列中NULL值的排序位置,FIRST表示将NULL值排在最前面,LAST表示将NULL值排在最后面,若不指定该选项, ASC默认为NULLS LAST, DESC默认为NULLS FIRST。
例子:
查询下表bonuses_depa中各工种的奖金信息,查询结果先按bonus升序排列,然后按name降序排列
select * from bonuses_depa order by bonus,name desc;
12. 数据限制
数据限制功能包括两个独立的子句,LIMIT子句和OFFSET子句
- LIMIT子句允许限制查询返回的行。 可以指定偏移量,以及要返回的行数或行百分比。 可以使用此子句实现top-N报表。要获得一致的结果,请指定ORDER BY子句以确保确定性排序顺序
LIMIT { count | ALL }
- OFFSET子句设置开始返回的位置
OFFSET start
使用方法
○ start:指定在返回行之前要跳过的行数。
○ count:指定要返回的最大行数。
○ start和count都被指定时,在开始计算要返回的count行之前会跳过start行
○ LIMIT 5,20与LIMIT 20 OFFSET 5及OFFSET 5 LIMIT 20 均表示跳过5行后输出20行记录
例子:
查询下表 bonuses_depa中的员工信息。通过增加LIMIT 2 OFFSET 1限定查询时跳过前1行后,查询总共2行数据
SELECT name, job, bonus FROM bonuses_depa LIMIT 2 OFFSET 1;