文章目录
- 多表查询
- 自连接
- 子查询
- 合并查询
基础查询中,再补充一个点:
在使用年薪进行降序排序中,我们有以下语句
//A:
select ename, sal*12+ifnull(comm,0) as '年薪' from emp order by 年薪 desc;
查询到的结果:
//B:
select ename, sal*12+ifnull(comm,0) as '年薪' from emp order by '年薪' desc;
查询到的结果:
A语句和B语句的执行结果不同,原因在于对于‘order by’子句中的排序字段的引用方式不同。
在A语句中,‘order by 年薪 desc ’中的‘年薪’是按照列名的方式引用的
,表示按照查询结果中的列名
进行排序。
在B语句中,‘order by '年薪’desc ’中的‘年薪’是作为字符串常量进行引用的
,表示按照字符串
进行排序,而不是按照查询结果中的列名进行排序。
因此,A语句中会按照查询结果中计算得到的年薪字段进行降序排序,而第二条语句会按照字符串常量进行排序,结果可能与预期不符。
正确的做法是使用第一种方式,即按照列名的方式引用排序字段
,确保按照查询结果中的实际字段进行排序。
多表查询
多表查询在没有指定连接条件的时候会形成笛卡尔积,这意味着每个表中的每一行都将与其他表中的每一行进行组合,生成一个结果集的所有可能组合。
例如,如果有两个表A和B,每个表分别有3行记录,执行以下查询:
SELECT * FROM table1, table2;
这将返回A表和B表之间的笛卡尔积,即9行的结果集。
最终我们可以通过where来约束笛卡尔积,查询到我们想要的结果。
(数据库来源:前文提到的雇员信息表(来自oracle 9i的经典测试表))
显示雇员名、雇员工资以及所在部门的名字,字因为上面的数据来自EMP和DEPT表,因此要联合查询:
select ename,sal,dname from emp,dept;
得到笛卡尔积,在此展示一部分:
其实我们只要emp表中的deptno = dept表中的deptno字段的记录,所以我们加上where条件
select ename,sal,dname from emp,dept where emp.deptno=dept.deptno;
自连接
自连接是一种特殊的多表查询操作,它指的是将表与自身进行连接。在自连接中,表被视为两个独立的实体,通过连接条件将它们关联起来。
语法:
select t1.column1, t2.column2 from table_name t1, table_name t2 where condition;
自连接常用于解决以下情况:
-
层级关系:当表中的数据具有层级结构时,可以使用自连接来处理这种层级关系。例如,员工表中的每个员工可能有一个上级领导,自连接可以用来查找员工及其对应的上级领导。
-
关联数据:当表中的数据与自身的其他数据存在关联关系时,可以使用自连接来查找这种关联数据。例如,某个表中的记录可能与同一表中的其他记录相关联,自连接可以用来查找这些关联数据。
举个例子:显示员工FORD的上级领导的编号和姓名
select leader.empno, leader.ename from emp leader, emp worker
where leader.empno=worker.mgr and worker.ename='FORD';
也可以用子查询实现:
select empno, ename from emp
where empno=(select mgr from emp where ename='FORD');
子查询
子查询是指在一个查询语句中嵌套使用另一个完整的查询语句。子查询可以嵌套在 SELECT、FROM、WHERE 或 HAVING 子句中,用于提供额外的条件、过滤数据或进行更复杂的查询操作。
- 单行子查询
返回一行记录的子查询
例子:显示SMITH同一部门的员工编号和名字
select * from emp
WHERE deptno = (select deptno from emp where ename='SMITH');
- 多行子查询
返回多行记录的子查询
in 关键字
:在SQL中,in 关键字用于指定一个条件,其中一个值匹配列表或子查询中的任何值。通常在 WHERE 子句中使用它来根据特定的值集过滤行。
例子:查询和10号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含10自己的
select ename, job, sal, deptno from emp
where job in (select distinct job from emp where deptno=10) and deptno!=10;
all 关键字
:在SQL中,all 关键字用于将一个值与列表或子查询中的所有值进行比较。它通常与比较运算符一起使用,如 >(大于)、<(小于)、=(等于)等。
例子:显示工资比部门30的所有员工的工资高的员工的姓名、工资和部门号
select ename, sal, deptno from emp
where sal > all(select sal from emp where deptno=30);
any 关键字
:在SQL中,any 关键字用于将一个值与列表或子查询中的任何值进行比较。它类似于 ALL 关键字,但只要条件对于列表或子查询中的至少一个值为真即可。
例子:显示工资比部门30的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门的员工)
select ename, sal, deptno from emp
where sal > any(select sal from emp where deptno=30);
- 多列子查询
多列子查询是指在子查询中返回多列的结果,然后将该结果作为外部查询的条件或结果之一。多列子查询可以用于各种情况,例如在 WHERE 子句中使用子查询作为条件、在 SELECT 语句中使用子查询作为列等。
需要注意的是,子查询返回的列数必须与外部查询中使用它的地方所需的列数相匹配。否则,将会引发语法错误或返回意外的结果。
例子:查询和SMITH的部门和岗位完全相同的所有雇员,不含SMITH本人
select empno, ename, job from emp
where (deptno, job) = (select deptno, job from emp
where ename='SMITH') and ename<>'SMITH';
- 在from子句中使用子查询
子查询语句出现在from子句中。这里要用到数据查询的技巧,把一个子查询当做一个临时表使用。
例子:显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资
//获取各个部门的平均工资,将其看作临时表
select ename, deptno, sal,format(asal,2) from emp,
(select avg(sal) asal, deptno dt from emp group by deptno) tmp
where emp.sal > tmp.asal and emp.deptno=tmp.dt;
例子:查找每个部门工资最高的人的姓名、工资、部门、最高工资
select ename, sal, deptno, ms from emp,
(select max(sal) ms,deptno dt from emp group by deptno) tmp
where emp.deptno=tmp.dt and emp.sal=tmp.ms;
例子:显示每个部门的信息(部门名,编号,地址)和人员数量
使用多表:
select dname, dept.deptno,loc,count(*) '部门人数' from emp,dept
where emp.deptndeptno=dept.deptno group by dept.deptno;
使用子查询:
select dept.deptno, dname, mycnt, loc from dept,
(select count(*) mycnt, deptno from emp group by deptno) tmp
where dept.deptno=tmp.deptno;
合并查询
在 SQL 中,可以使用 union 或 union all 运算符来合并查询结果集。这些运算符用于将两个或多个 SELECT 语句的结果合并成一个结果集。
union 运算符会合并并去重两个查询结果集,即它会删除重复的行。而 union all 运算符则会合并两个查询结果集,包括重复的行。
例子:将工资大于2500或职位是MANAGER的人找出来
union(去重):
mysql> select ename, sal, job from emp where sal>2500 union
-> select ename, sal, job from emp where job='MANAGER';
执行结果:
union all(不去重):
mysql> select ename, sal, job from emp where sal>2500
-> union all select ename,sal,job from emp where job='MANAGER';
执行结果:
需要注意的是,要使用 union 或 union all 运算符,两个查询的列数和列类型必须相同或兼容。否则,可能会引发错误。