06. SQL 基础--> 子查询

一、子查询

子查询就是位于SELECT、UPDATE、或DELETE语句中内部的查询

二、子查询的分类

单行子查询
    返回零行或一行

多行子查询
    返回一行或多行

多列子查询
    返回多列

相关子查询
    引用外部SQL语句中的一列或多列

嵌套子查询
    位于其它子查询中的查询

  

三、子查询语法

SELECT select_list
FROM table
WHERE expr operator
   (SELECT select_list
    FROM table);

子查询(内部查询)在执行主查询之前执行一次,然后主查询(外部查询)会使用该子查询的结果

四、子查询的规则

将子查询括在括号中
将子查询放置在比较条件的右侧
只有在执行排序Top-N分析时,子查询中才需要使用ORDER BY 子句
单行运算符用于单行子查询,多行运算符用于多行子查询

五、单行子查询

仅返回一行
使用单行的表较运算符:= ,>, >= ,< , <= ,<>

在WHERE 子句中使用子查询 

SQL> select ename,job from emp
     where empno = (
     select empno from emp
     where mgr = 7902 );

ENAME      JOB
---------- ---------
SMITH      CLERK

--使用分组函数的子查询

SQL> select ename,job,sal
     from emp
     where sal >
     (select avg(sal) from emp);

ENAME      JOB              SAL
---------- --------- ----------
JONES      MANAGER         2975
BLAKE      MANAGER         2850
CLARK      MANAGER         2450
SCOTT      ANALYST         3000
KING       PRESIDENT       5000
FORD       ANALYST         3000

--在HAVING子句中使用子查询

SQL> select deptno,min(sal)

  2  from emp

  3  group by deptno

  4  having min(sal) >

  5      (select min(sal)

  6       from emp

  7       where deptno = 20);

   DEPTNO   MIN(SAL)

---------- ----------

       30        950

       10       1300

--在FROM 子句中使用子查询

SQL> select empno,ename

  2  from

  3      (select empno,ename

  4       from emp

  5       where deptno = 20);

    EMPNO ENAME

---------- ----------

     7369 SMITH

     7566 JONES

     7788 SCOTT

     7876 ADAMS

     7902 FORD

--单行子查询中的常见错误

    --子查询的结果返回多于一行

   SQL> select empno,ename

     2  from emp

     3  where sal =

     4      (select sal     

     5       from emp

     6       where deptno = 20);

       (select sal

        *

   ERROR at line 4:

   ORA-01427: single-row subquery returns more than one row

   --子查询中不能包含ORDER BY子句

   SQL> select empno,ename

     2  from emp

     3  where sal >

     4      (select avg(sal)

     5       from emp

     6       order by empno);

        order by empno)

        *

   ERROR at line 6:

   ORA-00907: missing right parenthesis

   --子查询内部没有返回行,如下语句可以正确执行,但没有数据返回

   SQL> select ename,job

     2  from emp

     3  where empno =

     4      (select empno

     5       from emp

     6       where mgr = 8000);

   no rows selected

  

六、多行子查询

返回多个行

使用多行比较运算符IN ,ANY ,ALL

在多行子查询中使用IN 操作符 */

idle> select empno,ename,job
from emp
where sal in
    (select max(sal)
     from emp
     group by deptno);
  2    3    4    5    6
     EMPNO ENAME      JOB
---------- ---------- ---------
      7698 BLAKE      MANAGER
      7788 SCOTT      ANALYST
      7839 KING       PRESIDENT
      7902 FORD       ANALYST

  

--在多行子查询中使用ANY 操作符

idle> select empno,ename,job
from emp
where sal < any
    (select avg(sal)
     from emp
     group by deptno);
  2    3    4    5    6
     EMPNO ENAME      JOB
---------- ---------- ---------
      7369 SMITH      CLERK
      7900 JAMES      CLERK
      7876 ADAMS      CLERK
      7521 WARD       SALESMAN
      7654 MARTIN     SALESMAN
      7934 MILLER     CLERK
      7844 TURNER     SALESMAN
      7499 ALLEN      SALESMAN
      7782 CLARK      MANAGER
      7698 BLAKE      MANAGER

10 rows selected.

  

--在多行子查询中使用ALL 操作符

idle> select empno,ename,job
from emp
where sal > all
    (select avg(sal)
     from emp
     group by deptno);
  2    3    4    5    6
     EMPNO ENAME      JOB
---------- ---------- ---------
      7566 JONES      MANAGER
      7788 SCOTT      ANALYST
      7902 FORD       ANALYST
      7839 KING       PRESIDENT

  

/*

七、相关子查询

子查询中使用了主查询中的某些字段,主查询每扫描一行都要执行一次子查询 */

--查询工资高于同一部门的员工的部门号,姓名,工资

idle> select deptno,ename,sal
from emp outer
where sal >
    (select avg(sal)
     from emp inner
     where inner.deptno = outer.deptno);
  2    3    4    5    6
    DEPTNO ENAME	     SAL
---------- ---------- ----------
	30 ALLEN	    1600
	20 JONES	    2975
	30 BLAKE	    2850
	20 SCOTT	    3000
	10 KING 	    5000
	20 FORD 	    3000

6 rows selected.

--查询负责管理其它员工的员工记录(使用exists)

idle> select empno,ename
from emp outer
where exists
   (select empno
    from emp inner
    where inner.mgr = outer.empno);
  2    3    4    5    6
     EMPNO ENAME
---------- ----------
      7566 JONES
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7902 FORD

6 rows selected.

  

--查询不管理其它员工的职员(not exists)

idle> select empno,ename
from emp outer
where not exists
(select empno
from emp inner
where inner.mgr = outer.empno);  2    3    4    5    6  

     EMPNO ENAME
---------- ----------
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7654 MARTIN
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7934 MILLER

8 rows selected.

 

EXISTS 和NOT EXISTS 与IN 和NOT IN 的比较

EXISTS与IN的不同:

EXISTS只检查行的存在性,IN 要检查实际值的存在性(一般情况下EXISTS的性能高于IN)

NOT EXISTS 和NOT IN

当值列表中包含空值的情况下,NOT EXISTS 则返回true,而NOT IN 则返回false.

--看下面的查询,查询部门号不在emp表中出现的部门名称及位置

idle> select deptno,dname,loc
from dept d
where not exists
    (select 1
     from emp e
     where e.deptno = d.deptno);
  2    3    4    5    6
    DEPTNO DNAME	  LOC
---------- -------------- -------------
	40 OPERATIONS	  BOSTON

  

--IN与空值

idle> SELECT *
FROM emp e
WHERE e.empno NOT IN (
                       SELECT 7369 FROM dual
                       UNION ALL
                       SELECT NULL FROM dual
                      );
  2    3    4    5    6    7
no rows selected

idle>
idle> SELECT *
  FROM emp e
  WHERE e.empno IN (‘7369‘,NULL);
  2    3
     EMPNO ENAME      JOB           MGR HIREDATE         SAL       COMM    DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7369 SMITH      CLERK          7902 1980-12-17         800            20

注:子查询要包含在括号内

子查询一般放在比较条件的右侧

除非进行TOP-N 分析,否则不要在子查询中使用ORDER BY。 */

/*

八、多列子查询

1、成对比较

查询工资为部门最高的记录

idle> select * from scott.emp
where (sal,job) in
(select max(sal),job from scott.emp group by job);
  2    3
     EMPNO ENAME      JOB	       MGR HIREDATE	     SAL       COMM	DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7934 MILLER     CLERK	      7782 1982-01-23	    1300		    10
      7499 ALLEN      SALESMAN	      7698 1981-02-20	    1600	300	    30
      7839 KING       PRESIDENT 	   1981-11-17	    5000		    10
      7566 JONES      MANAGER	      7839 1981-04-02	    2975		    20
      7902 FORD       ANALYST	      7566 1981-12-03	    3000		    20
      7788 SCOTT      ANALYST	      7566 1987-04-19	    3000		    20

6 rows selected.

  

2、非成对比较,实现了与上述类似的功能

idle> select * from scott.emp
where sal in (select max(sal) from scott.emp group by job)
and job in (select distinct job from scott.emp);
  2    3
     EMPNO ENAME      JOB	       MGR HIREDATE	     SAL       COMM	DEPTNO
---------- ---------- --------- ---------- ---------- ---------- ---------- ----------
      7934 MILLER     CLERK	      7782 1982-01-23	    1300		    10
      7499 ALLEN      SALESMAN	      7698 1981-02-20	    1600	300	    30
      7566 JONES      MANAGER	      7839 1981-04-02	    2975		    20
      7788 SCOTT      ANALYST	      7566 1987-04-19	    3000		    20
      7902 FORD       ANALYST	      7566 1981-12-03	    3000		    20
      7839 KING       PRESIDENT 	   1981-11-17	    5000		    10

  

九、嵌套子查询

即位于子查询内部的子查询,嵌套层数最多可达层。然而应尽量避免使用嵌套子查询,使用表连接的查询性能会更高

idle> select deptno,Num_emp
from (select deptno,count(empno) as Num_emp from emp group by deptno) d
where Num_emp > 3;
  2    3
    DEPTNO    NUM_EMP
---------- ----------
	30	    6
	20	    5

注意:子查询对空值的处理
除了count(*)外,都会忽略掉空值  

时间: 2024-08-25 13:43:53

06. SQL 基础--> 子查询的相关文章

SQL 基础--&gt; 子查询

--========================= --SQL 基础--> 子查询 --========================= 一.子查询 子查询就是位于SELECT.UPDATE.或DELETE语句中内部的查询 二.子查询的分类 单行子查询 返回零行或一行 多行子查询 返回一行或多行 多列子查询 返回多列 相关子查询 引用外部SQL语句中的一列或多列 嵌套子查询 位于其它子查询中的查询 三.子查询语法 SQL> SELECT select_list FROM table WH

SQL Fundamentals: 子查询 || 行列转换(PIVOT,UNPIVOT,DECODE),设置数据层次(LEVEL...CONNECT BY)

SQL Fundamentals || Oracle SQL语言 子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5.在SELECT子句中使用子查询 6.WITH子句 子查询(进阶) 7.分析函数 8.行列转换 9.设置数据层次 八.行列转换 pivot和unpivot函数是Oracle 11g增加的新函数,利用此函数可以实现行列转换操作 按照原始方式实现,使用通用函数中的DECODE()函数 列字段的处理 SQ

SQL用子查询结果更新多个字段

作者:iamlasong 要求:表格的内容需要变更,变更的内容放在一个临时表中,用SQL语句更新正式表中多个字段. 如果更新一个字段,直接用字段名=子查询就可以了,多个字段更新,将字段在括号中并列写出即可,如下: update tb_jg t set t.jgfl = 'sd', (     t.zj_code, t.zj_mc) = (select a.zj_code, a.zj_mc from song_temp a where a.zj_code = t.zj_code) where ex

SQL优化-子查询&case&limit

load 导数据.notesdxtdb 数据库    total_time  475.60秒. 监控服务:仓颉 select t_.*, a.name acquirer_name,m.merchant_name, am.merchant_name acq_merchant_name,                   ag.name agency_name            from              (            select t.* ,               

SQL Fundamentals: 子查询 || 分析函数

子查询(基础) 1.认识子查询 2.WHERE子句中使用子查询 3.在HAVING子句中使用子查询 4.在FROM子句中使用子查询 5.在SELECT子句中使用子查询 6.WITH子句 子查询(进阶) 7.分析函数 8.行列转换 9.设置数据层次 七.分析函数 分析函数语法: 分窗操作的: 使用分析函数可以进行更为复杂的查询报表显示. 在分析函数中可以使用若干统计函数. 传统SQL的问题 虽然利用SQL之中提供的各种查询命令可以完成大部分的查询要求,但是还有许多功能是无法实现的,例如: 计算运行

SQL Server子查询填充DataSet时报500内部错误的解决办法

运行环境为Visual Studio 2010,数据库为SQL Server 2008. 执行下面SQL语句 SELECT SubsiteId, SubsiteTitle, count(CollectionID) CollectionNumber,count(LName) PlantNumber FROM (SELECT DISTINCT SubsiteId, SubsiteTitle, CollectionID, LName, CName FROM Cumplag_Garden_Plants

ThinkPHP3.2 SQL alias 子查询

SELECT info_key, info_value, info_status, edit_time FROM (SELECT * FROM `detail` WHERE login = '[email protected]' ORDER BY edit_time DESC  ) AS aaa GROUP BY info_key 希望通过Thinkphp实现基于alias的子查询,终于参考下面这个文章实现了. http://www.thinkphp.cn/update/122.html 如下是

SQL 数据库 子查询及示例

子查询,又叫做嵌套查询. 将一个查询语句做为一个结果集供其他SQL语句使用,就像使用普通的表一样,被当作结果集的查询语句被称为子查询. 子查询有两种类型: 一种是只返回一个单值的子查询,这时它可以用在一个单值可以使用的地方,这时子查询可以看作是一个拥有返回值的函数: 另外一种是返回一列值的子查询,这时子查询可以看作是一个在内存中临时存在的数据表. 示例: --创建一个数据库,建立一个部门表格和部门人员表格 Create database gongs --创建一个gongs的数据库 go use

SQL随着子查询结果更新多个字段

笔者:iamlasong 要求:表格内容需要改变,在临时表中内容的变化,使用SQL官方声明更新表若干领域. 假设更新一个字段,直接用字段名=子查询就能够了,多个字段更新,将字段在括号里并列写出就可以,例如以下: update tb_jg t set t.jgfl = 'sd', (     t.zj_code, t.zj_mc) = (select a.zj_code, a.zj_mc from song_temp a where a.zj_code = t.zj_code) where exi