SELECT count(*) 雇员总数 FROM emp;
[说明]count函数中还可以引用表达。因为分组函数会忽略NULL行,所以使用count(表达式)会显示非NULL的总计行数。如:
SELECT count(comm) 补助非空的雇员总数 FROM emp;
当使用分组函数时,有一些注意事项。
? 分组函数只能出现在选择列表、ORDER BY子句、HAVING子句中。 ? 当使用分组函数时,会忽略NULL行。
? 如果在选择列表中既包含了分组函数,也包含了其他列和表达式,那么这些列或表达式必须
出现在GROUP BY子句中。
? 当使用分组函数时,可以在函数中指定ALL和DISTINCE选项。其中ALL是默认选项,该
选项表示统计所有行数据(包括重复值);如果指定DISTINCT,则只会统计不同行值。下面是常用的分组函数:
2) GROUP BY和HAVING子句
GROUP BY子句用于对查询结果进行分组统计,HAVING子句用于限制分组显示结果。如果选择列表同时包含有列、表达式和分组函数,那么这些列和表达式必须出现在GROUP BY子句中。语法如下:
SELECT column,group_function FROM table [WHERE condition]
[GROUP BY group_by_expression] [HAVING group_condition] [ORDER BY expression];
? 使用GROUP BY进行单列分组
单列分组是指基于单列生成分组统计结果。当进行单列分组时,会基于分组列的每个不同值生成一个统计结果。
如:SELECT deptno 部门代码,avg(sal) 部门平均工资 FROM emp GROUP BY deptno;
? 使用GROUP BY进行多列分组
多列分组是指基于两个或两个以上的列生成分组统计结果。当进行多列分组时,会基于多个列的不同值生成统计结果。
如:SELECT deptno,job,avg(sal),max(sal) FROM emp GROUP BY deptno,job;
? 使用HAVING子句限制分组显示结果
HAVING 子句用于限制分组统计结果,并且HAVING子句必须跟在GROUP BY子句后面。 如:SELECT deptno,avg(sal),max(sal) FROM emp GROUP BY deptno
HAVING avg(sal)<2500;
? 使用ORDER BY 子句改变分组排序结果
当使用GROUP BY 子句执行分组统计时,默认情况下分以分组列的升序显示统计结果。如果要改变统计结果的显示顺序,那么需要使用ORDER BY子句. 如:SELECT deptno,avg(sal) FROM emp
GROUP BY deptno ORDER BY avg(sal);
? 使用数据分组的注意事项
当执行数据统计时,需要注意正确使用GROUP BY子句、WHERE子句和分组函数。具休要求如下:
21
? 分组函数只能出现在选择列表、HAVING子句和ORDER BY子句中
? 如果在SELECT语句中同时包含有GROUP BY、HAVING以及ORDER BY子句,那么
必须将ORDER BY子句放在最后。
? 如果选择列表包含有列、表达式和分组函数,那么这些列和表达式必须出现在GROUP
BY子句中,否则会显示错误信息。
如:SELECT deptno,job,avg(sal) FROM emp
GROUP BY deptno;(错误,因为job未出现在GROUP BY子句中) ? 当限制分组显示结果时,必须使用HAVING子句,而不能在WHERE子句中使用分组函
数,否则会显示错误信息。
如:SELECT deptno,AVG(sal) FROM emp
WHERE SUM(sal)>1000
GROUP BY deptno(错误:分组函数不能用在WHERE中)
6.2 连接查询
连接查询是指基于两个或两个以上表或视图的查询。在实际应用中,查询单个表可能无法满足应用程序的实际需求(例如显示SALES部门位置以及雇员名)。使用连接查询时的注意事项:
? 当使用连接查询时,必须在FROM子句后指定两个或两个以上的表。
? 当使用连接查询时,应该在列名前加表名作为前缀。但如果不同表之间列名不同,可以不加表句
作前缀。当使用连接查询时,必须在WHERE子句中指定有效的连接条件,否则会导致生成笛卡儿积。
? 如:SELECT dept.dname,emp.ename FROM dept,emp WHERE ept.dname=?SALES?; ? 当进行连接查询时,使用表别名可以简化连接查询语句。
如:SELECT d.dname,e.ename FROM dept d,emp e WHERE d.deptno=e.deptno;
6.3 相等连接(包括SQL:1999标准内连接、自然连接)
相等连接是指使用相等比较符(=)指定连接条件的连接查询,该类连接查询主要用于检索主从表之间的相关数据。语法:
SELECT table1.column,table2.column FROM table1,table2 WHERE table1.column1=table2.column2.; 如:SELECT e.ename,e.sal,d.dname FROM emp e,dept d
WHERE e.deptno=d.deptno(AND d.deptno=10);
6.4 不等连接
指在连接条件中使用除相等比较符外其他比较操作符的连接查询。主要用于在不同表之间显示特定范围的信息。
如:SELECT a.ename,a.sal,b.grade FROM emp a,salgrade b
WHERE a.sal BETWEEN b.losal AND b.hisal
22
6.5 自连接
自连接是指在同一张表之间的连接查询,它主要用在自参照表上显示上下级关系或者层次关系。自参照表是指在不同列之间具有参照关系或主从关系的表。如下表, EMPNO(雇员号) 7839 7566 7698 7782 。。。 ENAME KING JONES BLAKE CLARK 。。。 MGR(管理者号) 7839 7839 7839 。。。 根据EMPNO列和MGR列的对应关系,可以确定雇员JONES、BLAKE和CLARK的管理者为KING。
为了显示雇员及其管理者之间的对应关系,可以使用自连接。因为自连接是在同一张表之间的连接,所以必须定义表别名。
如:SELECT manager.ename FROM emp manager,emp worker
WHERE manager.empno=worker.mgr AND worker.ename=?BLAKE?;
6.6 [内连接和]外连接
内连接用于返回满足连接条件的记录;而外连接则是内连接的扩展,它不仅会返回满足连接条件的所有记录,而且还会返回不满足连接条件的记录。在Oracle Database 9i之前,连接语法都是在WHERE子句中指定的(+号实现);从9i开始,有专用语法(SQL:1999标准),格式如下:
SELECT table1.column,table2.column
FROM table1 [INNER | NATURAL | LEFT | RIGHT | FULL] JOIN table2 ON table1.column1=table2.column2;
6.6.1 内连接
用于返回满足连接条件的所有记录。默认情况下,在执行连接查询时如果没有指定任何连接操作符,那么这些连接查询都属于内连接。
如:SELECT a.dname,b.ename FROM dept a INNER JOIN emp b
ON a.deptno=b.deptno AND a.deptno=10; 从Oracle Database 9i开始,如果主表的主键列和从表的外部键列名称相同,那么还可以使用NATURAL JOIN关键字自动执行内连接操作。
如:SELECT dname,ename FROM dept NATURAL JOIN emp;
6.6.2 左外连接
不仅返回满足连接条件的所有记录,而且还会返回不满足连接条件的连接操作符左边表的其他行。 如:SELECT a.dname,b.ename FROM dept a LEFT JOIN emp b
ON a.deptno=b.deptno AND a.deptno=10
23
6.6.3 右外连接
不仅返回满足连接条件的所有记录,而且还会返回不满足连接条件的连接操作符右边表的其他行。
6.6.4 完全外连接
不仅返回满足连接条件的所有记录,而且还会返回不满足连接条件的所有其他行。 注释:外连接可以使用(+)操作符,但不建议用。
6.7 子查询
子查询是指嵌入在其他SQL语句中的SELECT语句,也称为嵌套查询。当在DDL语句中使用子查询时,可以带有ORDER BY子句;但如果在WHERE子句、SET子句中使用子查询,不能带有ORDER BY 子句。子查询具有以下作用:
? 通过在INSERT或CREATE TABLE语句中使用子查询,可以将源表数据追加到目标表。 ? 通过在UPDATE语句中使用子查询可以修改一列或多列的数据 ? 通过在WHERE、HAVING子句中使用子查询,可以提供条件值。
根据子查询返回结果的不同,子查询又分为单行子查询、多行子查询和多列子查询。
6.7.1 单行子查询(单列)
指只返回一行数据的子查询语句。当在WHERE子句中引用单行子查询时,可以使用单行比较符(=,〈,〈,〉=,〈=,〈〉〉。
如:SELECT ename,sal,deptno FROM emp
WHERE deptno=(SELECT deptno FROM emp WHERE ename=?SCOTT?);
6.7.2 多行子查询(单列)
指返回多行数据的子查询语句。当在WHERE子句中使用多行子查询时,必须使用多行比较符(IN,ALL,ANY)。
IN:匹配于子查询结果的任一个值即可
SELECT ename,job,sal,deptno FROM emp WHERE job IN (SELECT distinct job FROM emp WHERE deptno=10); ALL:必须要符合子查询结果的所有值
SELECT ename,sal,deptno FROM emp WHERE sal>all (SELECT sal FROM emp WHERE deptno=30); ANY:只要符合子查询结果的任一个值即可
SELECT ename,sal,deptno FROM emp WHERE sal>ANY (SELECT sal FROM emp WHERE deptno=30)
24
6.7.3 多列子查询
单行子查询是指子查询只返回单列单行数据,多行子查询是指子查询返回单列多行数据,二者都是针对单列而言的。
而多列子查询则是指返回多个列数据的子查询语句。当多列子查询返回单行数据时,在WHERE子句中可以使用单行比较符;当多列子查询返回多行数据时,有WHERE子句中必须使用多行比较符(IN、ANY、ALL)。
如:SELECT ename,job,sal,deptno FROM emp WHERE (deptno,job)=(SELECT deptno,,job FROM emp WHERE ename=‘SMITH’);
当使用子查询比较多个列的数据时,既可以使用成对比较,也可以使用非成对比较成对比较示例
SELECT ename,sal,comm,deptno FROM emp WHERE(sal,nvl(comm,-1)) IN (SELECT sal,nvl(comm,-1) FROM emp WHERE deptno=30);
非成对比较示例
SELECT ename,sal,comm,deptno FROM emp WHERE sal IN (SELECT sal FROM emp WHERE deptno=30) AND nvl(comm,-1) IN (SELECT nvl(comm,-1) FROM emp WHERE deptno=30);
6.7.4 其他子查询
6.7.4.1 相关子查询(通过EXISTS谓词实现)
SELECT ename,job,sal FROM emp WHERE EXISTS
(SELECT 1 FROM dept WHERE dept.deptno=emp.deptno AND dept.loc=‘NEW YORK’); 显示工作在NEW YORK的所有雇员的姓名,工作,工资及部门号)
6.7.4.2 在FROM子句中使用子查询(子查询作为视图对待,又称内嵌视图)
SELECT ename,job,sal FROM emp,(SELECT deptno,avg(sal) avgsal FROM emp GROUP BY deptno) d
WHERE emp.deptno=d.deptno and sal>d.avgsal;
注:当在FROM子句中使用子查询时,必须给予查询指定别名。
6.7.4.3 在DML语句中使用子查询 6.7.4.3.1
在INSERT语句中使用子查询
可以将一张表的数据装载到另一张表。
如:INSERT INTO employee(id,name,title,salary) SELECT empno,ename,job,sal FROM emp;
25