使用SQL语句

SQL是关系数据库的基本操作语言,它是应用程序与数据库进行交互操作的接口,SQL语言包括数据查询语言(SELECT)、数据操纵语言(INSERT、UPDATE、DELETE)、事务控制语言(COMMIT、ROLLBACK、SAVEPOINT)、数据定义语言(CREATE、ALTER、DROP等)、数据控制语言(GRANT、REVOKE)等五个部分

基本查询语句

简单查询语句

在关系数据库中,查询数据是使用SELECT语句来完成的。当检索表数据时,既可以检索所有列的数据,也可以指定检索特定列的数据。检索特定列的数据必须要清楚表的结构,通过使用命令DESCRIBE(可以简写为DESC)显示表结构。如显示部门表dept的表结构:

SQL> DESC dept;
Name   Type         Nullable Default Comments 
------ ------------ -------- ------- -------- 
DEPTNO NUMBER(2)                              
DNAME  VARCHAR2(14) Y                         
LOC    VARCHAR2(13) Y  

1、检索所有列
为了检索所有列,可以在 SELECT关键字后面指定星号(*),代表查询该表的所有数据,如:
SQL> SELECT * FROM dept;

DEPTNO DNAME          LOC
------ -------------- -------------
    10 ACCOUNTING     NEW YORK
    20 RESEARCH       DALLAS
    30 SALES          CHICAGO
    40 OPERATIONS     BOSTON

2、检索特定列
在SELECT关键字后面指定列名,如果有多列使用逗号(,)隔开,如:
SQL> SELECT deptno, dname FROM dept;

DEPTNO DNAME
------ --------------
    10 ACCOUNTING
    20 RESEARCH
    30 SALES
    40 OPERATIONS

3、检索日期列
日期数据的默认显示格式为“DD-MON-YY”,如果希望使用其它格式(如YYYY-MM-DD),那么必须使用 TO_CHAR函数进行转换。另外,不同语言、地区的日期显示结果会有所不同。
SQL> SELECT ename, TO_CHAR(hiredate, 'YYYY/MM/DD') FROM emp WHERE empno=7788;

ENAME      TO_CHAR(HIREDATE,'YYYY/MM/DD')
---------- ------------------------------
SCOTT      1987/04/19

4、取消重复行
在执行查询时,某些情况下可能会产生完全相同的数据结果,这可能是没有任何意义的,我们们可以使用 DISTINCT取消重复行的查询。如,显示所有部门号级岗位:
SQL> SELECT DISTINCT deptno, job from emp;

DEPTNO JOB
------ ---------
    20 CLERK
    30 SALESMAN
    20 MANAGER
    30 CLERK
    10 PRESIDENT
    30 MANAGER
    10 CLERK
    10 MANAGER
    20 ANALYST

9 rows selected

5、使用算术表达式
执行查询操作时可以在数字列上使用算术表达式(+、-、*、/)。如,显示雇员KING的全年工资为例:
SQL> SELECT sal*12 FROM emp WHERE ename='KING';

    SAL*12
----------
     60000

6、使用列别名
默认情况下,列标题是大写格式的列名或表达式。通过使用列别名,可以改变列标题的显示样式。列别名应该在列或者表达式之后,在二者之间可以加AS关键字。注意,如果列别名有大小写之分,并包含特殊字符或空格,必须要用双引号引住。,如:
SQL> SELECT ename AS 姓名, sal*12 年收入 FROM emp WHERE ename='KING';

姓名           年收入
---------- ----------
KING            60000

7、处理NULL
NULL表示未知值,既不是空格也不是0。给表插入数据时,如果没有给某列提供数据,并且该列没有默认值,那么其值为NULL。 注意,当算术表达式包含NULL时,其结果也是NULL,如:
SQL> SELECT ename, sal, comm, sal+comm FROM emp WHERE deptno=30;

ENAME            SAL      COMM   SAL+COMM
---------- --------- --------- ----------
ALLEN        1600.00    300.00       1900
WARD         1250.00    500.00       1750
MARTIN       1250.00   1400.00       2650
BLAKE        2850.00           
TURNER       1500.00      0.00       1500
JAMES         950.00           

使用 NVL函数处理NULL值,其语法格式为NVL(expr1,expr2),如果expr1为NULL则返回expr2;如果expr1不是NULL,则返回expr1。expr1、expr2可以是任意数据类型,但两者的数据类型要相匹配,如:
SQL> SELECT ename, sal, comm, sal+NVL(comm, 0) 月收入 FROM emp WHERE deptno=30;

ENAME            SAL      COMM     月收入
---------- --------- --------- ----------
ALLEN        1600.00    300.00       1900
WARD         1250.00    500.00       1750
MARTIN       1250.00   1400.00       2650
BLAKE        2850.00                 2850
TURNER       1500.00      0.00       1500
JAMES         950.00                  950

使用 NVL2函数处理NULL值,其语法格式为NVL2(expr1,expr2,expr3)。如果expr1不是NULL,则返回expr2;如果expr1是NULL,则返回expr3。参数expr1可以是任意数据类型,而expr2和expr3可以是除LONG之外的任何数据类型。expr1、expr2、expr3的数据类型要相匹配,如:
SQL> SELECT ename, sal, comm, NVL2(comm, sal+comm, sal) 月收入 FROM emp WHERE deptno=30;

ENAME            SAL      COMM     月收入
---------- --------- --------- ----------
ALLEN        1600.00    300.00       1900
WARD         1250.00    500.00       1750
MARTIN       1250.00   1400.00       2650
BLAKE        2850.00                 2850
TURNER       1500.00      0.00       1500
JAMES         950.00                  950

8、连接字符串“||”
有时为了显示更有意义的查询结果,需要使用“||”将多个字符串连接起来。连接数字可以在后面直接指定,如果要加入字符和日期值必须用单引号引住,如:
SQL> SELECT ename ||' is a ' || job "Employee Detail" FROM emp WHERE deptno=10;

Employee Detail
-------------------------
CLARK is a MANAGER
KING is a PRESIDENT
MILLER is a CLERK

WHERE子句限制查询数据

使用WHERE子句限制查询显示结果,也适用于UPDATE和DELETE语句,当一个表的数据量过大的时候尽量避免使用SELECT *查询所有行。WHERE关键字用于指定条件子句,返回值为TRUE检索相应行的数据,当编写条件子句时,需要使用到各种比较操作符,如:=、<>(!=)、>=、<=、>、<、BETWEEN…AND…、IN(list)、(NOT)LIKE、IS (NOT) NULL。

1、在WHERE条件子句中使用数字值,可以使用单引号,也可以直接使用数字值。

2、在WHERE条件子句中使用字符值,必须要用单引号引住。注意,字符值区分大小写,如:
SQL> SELECT job, sal FROM emp WHERE ename='SCOTT';

JOB             SAL
--------- ---------
CLERK       1500.00

为了避免字符值的大小写问题,可以使用函数UPPER或者LOWER转换大小写,如:
SQL> SELECT job, sal FROM emp WHERE ename='scott';

JOB             SAL
--------- ---------

SQL> SELECT job, sal FROM emp WHERE LOWER(ename)='scott';

JOB             SAL
--------- ---------
CLERK       1500.00

3、在WHERE子句中使用日期值
必须要用单引号引住,并且日期值必须要符合日期显示格式。如果日期值不符合默认日期显示格式,那么必须使用TO_DATE函数进行转换,如:
符合默认日期格式:
SQL> SELECT ename, sal, hiredate FROM emp WHERE hiredate > '01-1月-82';

ENAME            SAL HIREDATE
---------- --------- -----------
SCOTT        1500.00 1987/4/19
ADAMS        1100.00 1987/5/23
MILLER       1300.00 1982/1/23

不符合默认日期格式:
SQL> SELECT ename, sal, hiredate FROM emp WHERE hiredate > TO_DATE('1982-01-01', 'YYYY-MM-DD');

ENAME            SAL HIREDATE
---------- --------- -----------
SCOTT        1500.00 1987/4/19
ADAMS        1100.00 1987/5/23
MILLER       1300.00 1982/1/23

4、BETWEEN…AND…(包含边界)
显示工资在1000——2000之间的雇员为例,如:
SQL> SELECT ename, sal FROM emp WHERE sal BETWEEN 1100 AND 1600;

ENAME            SAL
---------- ---------
ALLEN        1600.00
WARD         1250.00
MARTIN       1250.00
SCOTT        1500.00
TURNER       1500.00
ADAMS        1100.00
MILLER       1300.00

5、LIKE操作符
LIKE操作符用于执行模糊查询。需要使用通配符”%”和”_”,其中“%”用于表示0个或多个字符,“_”用于表示一个字符,如果需要将通配符“%”,“_”用于字符值使用,那么必须使用ESCAPE选项和转义字符(在ESCAPE选项中指定转义字符的名称,在字符“%”或”_”前加转义字符)。如:
显示首字母为S的所有雇员名
SQL> SELECT ename FROM emp WHERE ename LIKE 'S%';

ENAME
----------
SMITH
SCOTT

显示第三个字母为大写A的所有雇员名
SQL> SELECT ename FROM emp WHERE ename LIKE '__A%';

ENAME
----------
BLAKE
CLARK
ADAMS

显示雇员名包含“_”的信息,此处用ESCAPE指定转义字符”/“,把转义字符后面的”_“当作普通字符处理
SQL> SELECT ename FROM emp WHERE ename LIKE '%/_%' ESCAPE '/';

ENAME
----------
FA_MALY

6、IN操作符
IN操作符用于执行列表匹配操作,当列或表达式结果匹配于列表中的任何一个值时,条件子句返回TRUE,如:
SQL> SELECT ename, sal FROM emp WHERE sal IN(1500, 1250);

ENAME            SAL
---------- ---------
WARD         1250.00
MARTIN       1250.00
SCOTT        1500.00
TURNER       1500.00

7、IS NULL操作符
IS NULL操作符用于检测列或者表达式的结果是否为NULL,如:
SQL> SELECT ename 总裁 FROM emp WHERE mgr IS NULL;

总裁
----------
KING

注意,当与NULL进行比较时,不要使用=,<>操作符,此时条件子句返回总是FALSE,如:
SQL> SELECT ename 总裁 FROM emp WHERE mgr=NULL;

总裁
----------

8、逻辑操作符AND、OR、NOT
逻辑操作符的优先级低于任一种比较操作符,在这三个操作符中,NOT优先级最高,AND次之,OR最低。可以使用括号改变优先级。NOT操作符主要与BETWEEN…AND、LIKE、IN、IS NULL结合使用,如:
显示部门20中岗位CLERK的雇员信息
SQL> SELECT ename, sal FROM emp WHERE deptno=20 AND job='CLERK';

ENAME            SAL
---------- ---------
SMITH          10.00
SCOTT        1500.00
ADAMS        1100.00

显示工资高于2500或岗位为MANAGER的雇员信息
SQL> SELECT ename, sal FROM emp WHERE sal>2500 OR job='MANAGER';

ENAME            SAL
---------- ---------
FA_MALY      8000.00
JONES        2975.00
BLAKE        2850.00
CLARK        2450.00
KING         5000.00
FORD         3000.00

显示补助非空的雇员信息
SQL> SELECT ename, comm FROM emp WHERE comm IS NOT NULL;

ENAME           COMM
---------- ---------
FA_MALY      1000.00
ALLEN         300.00
WARD          500.00
MARTIN       1400.00
TURNER          0.00

使用ORDER BY子句排序

执行查询操作时,默认情况下会按照行数据插入的先后顺序来显示行数据。在实际应用中往往经常要对数据进行排序操作,以显示更直观的数据。数据排序使用ORDER BY子句来完成。[ORDER BY expr[ASC|DESC]],expr用于指定要排序的列或表达式,ASC用于指定升序排序(默认),DESC用于指定降序排序。注意,当在SELECT语句中同时包含多个子句(WHERE、GROUP BY、HAVING、ORDER BY等)时,ORDER BY必须是最后一个子句。

1、升序排序
排序操作时,默认就是升序排序,既可以指定关键字ASC,也可以不指定。注意,当以特定列执行升序排序时,如果排序列存在NULL行,那么NULL行会显示在最后面,如:
SQL> SELECT ename, comm FROM emp WHERE deptno=30 ORDER BY comm;

ENAME           COMM
---------- ---------
TURNER          0.00
ALLEN         300.00
WARD          500.00
MARTIN       1400.00
JAMES      
BLAKE      

2、降序排序
当执行降序排序时,必须要指定DESC关键字。注意,当以特定列执行降序排序时,如果排序列存在NULL行,那么NULL行会显示在最前面,如:
SQL> SELECT ename, comm FROM emp WHERE deptno=30 ORDER BY comm DESC;

ENAME           COMM
---------- ---------
BLAKE      
JAMES      
MARTIN       1400.00
WARD          500.00
ALLEN         300.00
TURNER          0.00

3、使用多列排序
使用ORDER BY进行排序时,也可以基于多个列或多个表达式进行排序。当以多个列或多个表达式进行排序时,首先按照第一个列或表达式进行排序,当存在相同数据时,再以第二个列或表达式进行排序。如,以部门号升序,工资降序显示雇员信息:
SQL> SELECT ename, deptno, sal FROM emp ORDER BY deptno, sal DESC;

ENAME      DEPTNO       SAL
---------- ------ ---------
FA_MALY        10   8000.00
KING           10   5000.00
CLARK          10   2450.00
MILLER         10   1300.00
FORD           20   3000.00
JONES          20   2975.00
SCOTT          20   1500.00
ADAMS          20   1100.00
SMITH          20     10.00
BLAKE          30   2850.00
ALLEN          30   1600.00
TURNER         30   1500.00
WARD           30   1250.00
MARTIN         30   1250.00
JAMES          30    950.00

4、使用非选择列表列进行排序
多数情况下会在选择列表中包含排序列,但选择列表也可以不包含任何排序列,如,以部门编号降序显示部门名:
SQL> SELECT dname FROM dept ORDER BY deptno DESC;

DNAME
--------------
OPERATIONS
SALES
RESEARCH
ACCOUNTING

5、使用列别名排序
以降序显示部门为30的雇员全年工资为例:
SQL> SELECT deptno, ename, NVL2(comm, sal+comm, sal)*12 年收入 FROM emp WHERE deptno=30 ORDER BY 年收入 DESC;

DEPTNO ENAME          年收入
------ ---------- ----------
    30 BLAKE           34200
    30 MARTIN          31800
    30 ALLEN           22800
    30 WARD            21000
    30 TURNER          18000
    30 JAMES           11400

6、使用列位置编号排序
如果列名或表达式名称很长,那么可以按照列或表达式在选择列表中的位置进行排序,位置从1开始。另外当使用UNION、UNION ALL、INTERSECT、MINUS等集合操作符合并查询结果时,如果选择列表中的列名不同,并且希望进行排序,那么必须使用列位置。

选择列表中列名相同,emp表和dept表中的deptno升序排列
SQL> SELECT deptno, ename FROM emp union SELECT deptno, dname FROM dept ORDER BY deptno;

DEPTNO ENAME
------ --------------
    10 ACCOUNTING
    10 CLARK
    10 FA_MALY
    10 KING
    10 MILLER
    20 ADAMS
    20 FORD
    20 JONES
    20 RESEARCH
    20 SCOTT
    20 SMITH
    30 ALLEN
    30 BLAKE
    30 JAMES
    30 MARTIN
    30 SALES
    30 TURNER
    30 WARD
    40 OPERATIONS

emp表中的empno和dept表中的deptno升序排列,选择列表中列名不同,但都要以列表中的第一列进行排序,使用列位置进行排序
SQL> SELECT deptno, dname FROM dept 
  2  UNION 
  3  SELECT empno, ename FROM emp 
  4  ORDER BY 1;

    DEPTNO DNAME
---------- --------------
        10 ACCOUNTING
        20 RESEARCH
        30 SALES
        40 OPERATIONS
      1314 FA_MALY
      7369 SMITH
      7499 ALLEN
      7521 WARD
      7566 JONES
      7654 MARTIN
      7698 BLAKE
      7782 CLARK
      7788 SCOTT
      7839 KING
      7844 TURNER
      7876 ADAMS
      7900 JAMES
      7902 FORD
      7934 MILLER

DML语句

DML(INSERT、UPDATE、DELETE)语句用于操纵表视图的数据。

INSERT数据

INSERT语句既可以为表插入单行数据,也可以通过子查询将一张表的多行数据插入到另一张表中。Oracle 9i开始还提供了多表插入功能,即使用一条INSERT语句同时为多张表插入数据。使用INSERT语句插入数据时应注意:
       为数字列插入数据可以直接提供,为字符和日期列插入数据要使用单引号
       插入数据必须要满足约束规则,必须要为主键和NOT NULL列插入数据
      插入数据时,数据必须要与列的个数和顺序保持一致

1、插入单行数据
语法:INSERT INTO <table> [(column[,column,…])] VALUES (value[,value,…])
table用于指定表名或视图名,既可以指定列列表,也可以不指定。如果不指定列列表,那么在VALUES子句中必须要为每个列提供数据,并且数据顺序、类型要与表列完全一致。如:

为了不破坏emp,dept表数据,这里依据它们的表结构重新建立空的emp2表和dept2表
SQL> CREATE table dept2 AS SELECT * FROM dept WHERE 1=2;

Table created

SQL> CREATE table emp2 AS SELECT * FROM emp WHERE 1=2;

Table created

不使用列的列表插入单行数据
INSERT INTO dept2 VALUES('50', 'IT', 'BJ');

使用列的列表插入单行数据
未出现在列表中的列为NULL,但是必须为主键和NOT NULL插入数据
SQL> INSERT INTO emp2(empno, ename, job, mgr, hiredate) VALUES (1234, 'TT', 'C++工程师', 7788, '08-8月-2012');

使用特定格式插入日期值
默认情况下日期值必须要与日期格式、日期语言匹配,如果用户希望使用习惯方式插入日期数据,那么必须要使用TO_DATE函数进行转换。
SQL> INSERT INTO emp2(empno, ename, job, mgr, hiredate) VALUES (5678, 'TT', 'Web工程师', 8899, TO_DATE('2010/08/11', 'YYYY/MM/DD'));

使用DEFAULT提供数据
当使用DEFAULT时,如果列有默认值便使用其默认值,没有便为NULL
SQL> CREATE table dept3 (
  2  deptno NUMBER(2),
  3  dname VARCHAR2(14),
  4  loc VARCHAR2(13) DEFAULT 'BJ'
  5  );
 
SQL> INSERT INTO dept3 VALUES(80, '经融', DEFAULT);

1 row inserted

SQL> select * from dept3;

DEPTNO DNAME          LOC
------ -------------- -------------
    80 经融           BJ


2、使用子查询插入数据
语法:INSERT INTO <table> [(column[,column,…])] subQuery
当使用子查询插入数据时,INSERT列的数据类型和个数必须要与子查询列的数据类型和个数完全匹配。
SQL> INSERT INTO dept2(deptno, dname, loc) SELECT * FROM dept;

4 rows inserted

使用子查询直接装载
SQL> INSERT /* +APPEND */ INTO dept2(deptno, dname, loc) SELECT * FROM dept;

使用/* +APPEND*/表示直接装载方式,当要装载大批量数据时,此种方法比上述方法更优。

3、使用多表插入数据
从Oracle 9i开始可以使用INSERT语句将某张表的数据同时插入到多张表中。

使用ALL操作符执行多表插入,将emp表中的部门10的数据插入到dept10中,部门20的数据插入到dept20中,其它数据插入到others表中。
SQL> INSERT ALL
  2  WHEN deptno=10 THEN INTO dept10
  3  WHEN deptno=20 THEN INTO dept20
  4  ELSE INTO others
  5  SELECT * FROM emp;

15 rows inserted

SQL> SELECT * FROM dept10;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 1314 FA_MALY    CLERK      7788 2012/8/8      8000.00   1000.00     10
 7782 CLARK      MANAGER    7839 1981/6/9      2450.00               10
 7839 KING       PRESIDENT       1981/11/17    5000.00               10
 7934 MILLER     CLERK      7782 1982/1/23     1300.00               10

SQL> SELECT * FROM dept20;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7369 SMITH      CLERK      7902 1980/12/17      10.00               20
 7566 JONES      MANAGER    7839 1981/4/2      2975.00               20
 7788 SCOTT      CLERK      7566 1987/4/19     1500.00               20
 7876 ADAMS      CLERK      7788 1987/5/23     1100.00               20
 7902 FORD       ANALYST    7566 1981/12/3     3000.00               20

SQL> SELECT * FROM others;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7499 ALLEN      SALESMAN   7698 1981/2/20     1600.00    300.00     30
 7521 WARD       SALESMAN   7698 1981/2/22     1250.00    500.00     30
 7654 MARTIN     SALESMAN   7698 1981/9/28     1250.00   1400.00     30
 7698 BLAKE      MANAGER    7839 1981/5/1      2850.00               30
 7844 TURNER     SALESMAN   7698 1981/9/8      1500.00      0.00     30
 7900 JAMES      CLERK      7698 1981/12/3      950.00               30

6 rows selected

使用FIRST操作符执行多表插入
SQL> INSERT FIRST
  2  WHEN deptno=10 THEN INTO dept10 
  3  WHEN deptno=20 THEN INTO dept20 
  4  WHEN job='CLERK' THEN INTO clerk
  5  ELSE INTO others
  6  SELECT * FROM emp;

15 rows inserted

SQL> select * from emp;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 1314 FA_MALY    CLERK      7788 2012/8/8      8000.00   1000.00     10
 7369 SMITH      CLERK      7902 1980/12/17      10.00               20
 7499 ALLEN      SALESMAN   7698 1981/2/20     1600.00    300.00     30
 7521 WARD       SALESMAN   7698 1981/2/22     1250.00    500.00     30
 7566 JONES      MANAGER    7839 1981/4/2      2975.00               20
 7654 MARTIN     SALESMAN   7698 1981/9/28     1250.00   1400.00     30
 7698 BLAKE      MANAGER    7839 1981/5/1      2850.00               30
 7782 CLARK      MANAGER    7839 1981/6/9      2450.00               10
 7788 SCOTT      CLERK      7566 1987/4/19     1500.00               20
 7839 KING       PRESIDENT       1981/11/17    5000.00               10
 7844 TURNER     SALESMAN   7698 1981/9/8      1500.00      0.00     30
 7876 ADAMS      CLERK      7788 1987/5/23     1100.00               20
 7900 JAMES      CLERK      7698 1981/12/3      950.00               30
 7902 FORD       ANALYST    7566 1981/12/3     3000.00               20
 7934 MILLER     CLERK      7782 1982/1/23     1300.00               10

15 rows selected

SQL> select * from dept10;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 1314 FA_MALY    CLERK      7788 2012/8/8      8000.00   1000.00     10
 7782 CLARK      MANAGER    7839 1981/6/9      2450.00               10
 7839 KING       PRESIDENT       1981/11/17    5000.00               10
 7934 MILLER     CLERK      7782 1982/1/23     1300.00               10

SQL> select * from dept20;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7369 SMITH      CLERK      7902 1980/12/17      10.00               20
 7566 JONES      MANAGER    7839 1981/4/2      2975.00               20
 7788 SCOTT      CLERK      7566 1987/4/19     1500.00               20
 7876 ADAMS      CLERK      7788 1987/5/23     1100.00               20
 7902 FORD       ANALYST    7566 1981/12/3     3000.00               20

SQL> select * from clerk
  2  ;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7900 JAMES      CLERK      7698 1981/12/3      950.00               30

SQL> select * from others;

EMPNO ENAME      JOB         MGR HIREDATE          SAL      COMM DEPTNO
----- ---------- --------- ----- ----------- --------- --------- ------
 7499 ALLEN      SALESMAN   7698 1981/2/20     1600.00    300.00     30
 7521 WARD       SALESMAN   7698 1981/2/22     1250.00    500.00     30
 7654 MARTIN     SALESMAN   7698 1981/9/28     1250.00   1400.00     30
 7698 BLAKE      MANAGER    7839 1981/5/1      2850.00               30
 7844 TURNER     SALESMAN   7698 1981/9/8      1500.00      0.00     30

当使用FIRST操作符进行多表插入时,如果数据已经满足了先前条件,并且已经被插入到某表,那么该行数据在后续插入操作中不会被再次使用。上述实例部门10和20中工作为"CLERK”的记录就没有在后续操作中插入到clerk表中。

UPDATE数据

使用UPDATE语句更新数据时,既可以使用表达式更新列值,也可以使用子查询更新一列或多列的值。注意:如果要更新字符或日期列,要用单引号引住;更新数据时,数据必须满足约束条件;数据必须要与列的数据类型匹配。

1、使用表达式更新数据
注意,当执行UPDATE语句时未指定WHERE子句,则会修改表中所有的数据。
语法:UPDATE <table|view> SET <column> = <value> [, <column> = <value> ] [WHERE <condition>];

更新单列数据
SQL> UPDATE emp SET sal=2460 WHERE ename='SCOTT';

更新多列数据
当更改多列时,列之间用逗号(,)分隔开
SQL> UPDATE emp SET sal=sal-460, comm=500 WHERE ename='SCOTT';

更新日期列数据
更新时数据格式一定要与默认日期格式、日期语言相匹配。如果使用习惯方式指定日期值,需要使用TO_DATE函数进行转换。
UPDATE emp SET hiredate=TO_DATE('2012/08/01', 'YYYY/MM/DD') WHERE ename='SCOTT';

使用DEFAULT选项更新数据
SQL> select * from dept3;

DEPTNO DNAME          LOC
------ -------------- -------------
    80 经融           BJ
    90 产品研发       上海

SQL> desc dept3;
Name   Type         Nullable Default Comments 
------ ------------ -------- ------- -------- 
DEPTNO NUMBER(2)    Y                         
DNAME  VARCHAR2(14) Y                         
LOC    VARCHAR2(13) Y        'BJ'             

SQL> UPDATE dept3 SET loc=DEFAULT WHERE deptno=90;

1 row updated

SQL> SELECT * FROM dept3;

DEPTNO DNAME          LOC
------ -------------- -------------
    80 经融           BJ
    90 产品研发       BJ


2、使用子查询更新数据

更新关联数据
当更新关联数据时,使用子查询可以降低网络开销。假设你希望雇员SCOTT的sal、job、comm与雇员SMITH完全相同,如果使用表达式或列值进行修改需要先取得SMITH的相应值,再进行SCOTT雇员的相关修改。使用子查询只需一条语句就可以,如:
UPDATE emp SET (sal, comm, job) = (SELECT sal, comm, job FROM emp WHERE ename='SMITH') WHERE ename='SCOTT';

复制表数据
通过使用子查询,可以基于一张表修改另一张表的数据。

DELETE数据

使用DELETE语句既可以删除一条语句,也可以删除多条语句。
语法:DELETE FROM <table|view> [WHERE <condition>];
当使用DELETE语句删除数据时,如果不指定WHERE条件子句,那么会删除表或视图的所有行。

1、删除满足条件的语句
DELETE FROM emp WHERE ename='FA_MALY';

2、删除表的所有数据
不指定WHERE子句就会删除表的所有数据。
SQL> delete from dept2;

13 rows deleted

3、使用TRUNCATE TABLE截断表
当使用DELETE语句删除表的所有数据时,不会释放表所占用的空间,如果用户确定需要删除表的所有数据,使用TRUNCATE TABLE语句速度更快。
SQL> TRUNCATE TABLE others;

Table truncated

注意,DELETE的操作可以回退,但TRUNCATE语句的操作不能回退

4、使用子查询删除数据
解雇SALES部门的所有雇员,首先创建一个emp表的副本newemp:
create table newemp as select * from emp;
 
SQL> DELETE FROM newemp WHERE deptno=(SELECT deptno FROM dept WHERE dname='SALES');

6 rows deleted

5、删除主表数据的注意事项
当用DELETE语句删除数据时注意:当删除主表数据时,必须要确保从表不存在相关记录,否则会显示错误信息,或者定义触发器级联删除。


事务控制语句

事务用于确保数据库数据的一致性,由一组相关的DML语句组成。该组DML语句执行的操作要么全部成功,要么全部失败。数据库事务主要由INSERT、UPDATE、DELETE和SELECT…FOR UPDATE语句组成。当在应用程序中执行第一条SQL语句时事务开始;当执行COMMIT或ROLLBACK语句时事务结束。

事务和锁

当执行事务操作(DML语句)时,Oracle会在被作用表上加表锁,以防止其他用户改变表结构;同时会在被作用行上加行锁,以防止其他事务在相应行上执行DML操作。在Oracle数据库中,为了确保数据库数据的读一致性,不允许其它用户读取脏数据(未提交事务)。
会话A:
SQL> UPDATE newemp SET sal=sal*100 WHERE ename='SCOTT';

1 row updated

SQL> SELECT sal FROM newemp WHERE ename='SCOTT';

      SAL
---------
  1000.00

会话B:
SQL> SELECT sal FROM newemp WHERE ename='SCOTT';

       SAL
----------
        10

提交事务

使用COMMIT语句可以提交事务。当执行了COMMIT语句之后,会确认事务变化、结束事务、删除保存点、释放锁。当使用COMMIT语句结束事务之后,其它会话将可以查看事务变化后的新数据。

会话A提交事务,然后在会话B中便可以看到更新后的数据:
会话B:
SQL> SELECT sal FROM newemp WHERE ename='SCOTT';

       SAL
----------
      1000

注意,出现以下情况时会自动提交事务:
当执行DDL语句时会自动提交事务,例如CREATE TABLE、ALTER TABLE、DROP TABLE等语句
当执行TCL语句(GRANT、REVOKE)时
当退出SQL*Plus时

回退事务

保存点(SAVEPOINT):保存点是事务中的一点,用于取消部分事务。当事务结束时,会自动删除该事务所定义的所有保存点。在执行ROLLBACK命令时,通过指定保存点可以取消部分事务。如下图所示:
使用SQL语句_第1张图片

1、设置保存点
使用SQL命令SAVEPOINT设置保存点。开发人员在编写程序时,也可以使用包DBMS_TRANSACTION的过程SAVEPOINT来设置保存点。
SQL> savepoint a;

Savepoint created

SQL> exec dbms_transaction.savepoint('b');

PL/SQL procedure successfully completed

2、取消部分事务
使用ROLLBACK TO命令回退到保存点取消部分事务,也可以使用包DBMS_TRANSACTION的过程ROLLBACK_SAVEPOINT。
SQL> rollback to a;
 
SQL> exec dbms_transaction.rollback_savepoint('a');

PL/SQL procedure successfully completed

3、取消全部事务
使用ROLLBACK命令取消全部事务。编写应用程序时也可以使用包DBMS_TRANSACTION的过程ROLLBACK取消全部事务。
SQL> rollback;
 
SQL> exec dbms_transaction.rollback;


只读事务

只读事务是指只允许执行查询操作,而不允许执行任何DML操作的事务。当使用只读事务时,可以确保用户取得特定时间点的数据。在设置了只读事务之后,尽管其它会话可能会提交新事务,但只读事务将不会取得新的数据变化,从而确保取得特定时间点的数据信息。注意,当设置只读事务时,该语句必须是事务开始的第一条语句。使用SQL命令SET TRANSACTION READ ONLY设置只读事务,在应用程序中,也可以使用过程DBMS_TRANSACTION.READ_ONLY设定。

会话A:
SQL> SET TRANSACTION READ ONLY;

Transaction set

SQL> UPDATE newemp SET sal=800 WHERE ename='SCOTT';

UPDATE newemp SET sal=800 WHERE ename='SCOTT'

ORA-01456: 不能在 READ ONLY 事务处理中执行插入/删除/更新操作

会话B:
SQL> UPDATE newemp SET sal=1234 WHERE ename='SCOTT';

已更新 1 行。

COMMIT;

会话A:
SQL> SELECT sal FROM newemp WHERE ename='SCOTT';

      SAL
---------
  1000.00


顺序事务

只读事务可以使得用户取得特定时间点的数据信息,但是会话将不能执行INSERT/UPDATE/DELETE等DML操作。为了使得用户可以取得特定时间点的数据,并且允许执行DML操作,可以使用顺序事务。通过SQL命令SET TRANSACTION ISOLATION LEVEL SERIALIZABLE设置。注意:当设置顺序事务时,该语句必须是事务开始的第一条语句。

使用SQL语句_第2张图片


数据分组

在关系数据库中,数据分组是通过使用GROUP BY子句、分组函数以及HAVING子句共同实现的。其中GROUP BY子句用于指定要分组的列(如DEPTNO),而分组函数则用于显示统计结果(如COUNT、AVG、SUM等),HAVING子句则用于限制分组显示结果。

分组函数

分组函数用于统计表的数据。与单行函数不同,分组函数作用于多行,并返回一个结果,所以有时也被称为多行函数。一般情况下,分组函数要与GROUP BY子句结合使用,如果忽略了,那么会汇总所有的行并产生一个结果。常用的分组函数有:
        MAX:取得列或表达式的最大值,适用于任何数据类型
         ● MIN:取得列或表达式的最小值,适用于任何数据类型
        
AVG:取得列或表达式的平均值,适用于数字类型
         SUM:取得列或表达式的总和,适用于数字类型
         COUNT:取得总计行数
         VARIANCE:取得列或表达式的方差,适用于数字类型,当只有一行数据时,其返回值为0
         STDDEV:取得列或表达式的标准偏差,适用于数字类型,当只有一行数据时,其返回值为0

当使用分组函数时,分组函数只能出现在选择列表、ORDER BY和HAVING子句中,而不能出现在WHERE和GROUP BY子句中。另外,使用分组函数还有以下一些注意事项:
         使用分组函数时,除了函数COUNT(*)之外,其它分组函数都会忽略NULL行。
         ● 当执行SELECT语句时,如果选择列表同时包含列、表达式和分组函数,那么这些列和表达式必须出现在GROUP BY子句中。
         当使用分组函数时,在分组函数中可以指定ALL和DISTINCT选项。其中ALL是默认选项,该选项表示统计所有行数据(包括重复行);如果指定DISTINCT,则只会统计不同行值。


1、取得最大值和最小值
SQL> SELECT max(sal), min(sal) FROM emp;

  MAX(SAL)   MIN(SAL)
---------- ----------
      5000         10

2、取得平均值和综合
SQL> SELECT avg(sal), sum(sal) FROM emp;

  AVG(SAL)   SUM(SAL)
---------- ----------
1803.21428      25245

3、取得总计行数
SQL> SELECT count(*) FROM emp;

  COUNT(*)
----------
        14

在COUNT函数中还可以指定列或表达式。因为分组函数会忽略NULL行,所以使用表达式count(表达式)会显示NOT NULL的总计行数。
SQL> SELECT count(comm) FROM emp;

COUNT(COMM)
-----------
          4

4、取得方差和标准差
SQL> SELECT variance(sal), stddev(sal) FROM emp;

VARIANCE(SAL) STDDEV(SAL)
------------- -----------
1783936.95054 1335.641026


5、取消重复值
SQL> SELECT count(deptno) AS distinct_dept FROM emp;

DISTINCT_DEPT
-------------
           14

SQL> SELECT count(distinct deptno) AS distinct_dept FROM emp;

DISTINCT_DEPT
-------------
            3

GROUP BY和HAVING

GROUP BY子句用于对查询结果进行分组统计,而HAVING子句则用于限制分组显示结果。注意,如果在选择列表中同时包含有列、表达式和分组函数,那么这些列和表达式必须出现在GROUP BY子句中。

1、使用GROUP BY进行单列分组
显示每个部门的最高工资和最低工资
SQL> SELECT deptno, max(sal), min(sal) FROM emp GROUP BY deptno ORDER BY deptno;

DEPTNO   MAX(SAL)   MIN(SAL)
------ ---------- ----------
    10       5000       1300
    20       3000         10
    30       2850        950


2、使用GROUP BY进行多列分组
多列分组是指在GROUP BY子句中使用两个或两个以上的列生成分组统计结果。
显示每个部门每种岗位的最高工资和平均工资
SQL> SELECT deptno, job, max(sal), avg(sal) FROM emp GROUP BY deptno, job ORDER BY deptno;

DEPTNO JOB         MAX(SAL)   AVG(SAL)
------ --------- ---------- ----------
    10 CLERK           1300       1300
    10 MANAGER         2450       2450
    10 PRESIDENT       5000       5000
    20 ANALYST         3000       3000
    20 CLERK           1100 373.333333
    20 MANAGER         2975       2975
    30 CLERK            950        950
    30 MANAGER         2850       2850
    30 SALESMAN        1600       1400


3、使用HAVING子句限制分组显示结果
HAVING子句必须跟在GROUP BY子句后面,如:平均工资低于2000的部门号,平均工资及最高工资。

SQL> SELECT deptno, avg(sal), max(sal) FROM emp GROUP BY deptno HAVING avg(sal)<2000;

DEPTNO   AVG(SAL)   MAX(SAL)
------ ---------- ----------
    30 1566.66666       2850
    20       1419       3000

使用GROUP BY子句、WHERE子句和分组函数有以下一些注意事项:
分组函数只能出现在选择列表、HAVING子句和ORDER BY子句中
如果在SELECT语句中同时包含有GROUP BY,HAVING以及ORDER BY子句,则必须将ORDER BY子句放在最后。默认情况下,当使用GROUP BY子句统计数据时,会自动按照分组列的升序方式显示统计结果。通过ORDER BY子句可以改变数据分组的排序方式。
如果选择别表包含有列、表达式和分组函数,那么这些列和表达式必须出现在GROUP BY子句中,否则会出错:
SQL> SELECT deptno, job FROM emp GROUP BY deptno;

SELECT deptno, job FROM emp GROUP BY deptno

ORA-00979: 不是 GROUP BY 表达式

当限制分组显示结果时,必须要使用HAVING子句,而不能在WHERE子句中使用分组函数限制分组显示结果


ROLLUP和CUBE

ROLLUP和CUBE用于产生横向和纵向的统计结果。

1、使用ROLLUP操作符
显示每部门每岗位的平均工资 、每部门的平均工资、所有雇员平均工资为例:
SQL> SELECT deptno, job, avg(sal) FROM emp GROUP BY ROLLUP (deptno, job) ORDER BY deptno;

DEPTNO JOB         AVG(SAL)
------ --------- ----------
    10 CLERK           1300
    10 MANAGER         2450
    10 PRESIDENT       5000
    10           2916.66666
    20 ANALYST         3000
    20 CLERK     373.333333
    20 MANAGER         2975
    20                 1419
    30 CLERK            950
    30 MANAGER         2850
    30 SALESMAN        1400
    30           1566.66666
                 1803.21428

2、使用CUBE操作符
显示每部门每岗位平均工资、部门平均工资、岗位平均工资、所有雇员平均工资为例:
SQL> SELECT deptno, job, avg(sal) FROM emp GROUP BY CUBE (deptno, job) ORDER BY deptno;

DEPTNO JOB         AVG(SAL)
------ --------- ----------
    10 CLERK           1300
    10 MANAGER         2450
    10 PRESIDENT       5000
    10           2916.66666
    20 ANALYST         3000
    20 CLERK     373.333333
    20 MANAGER         2975
    20                 1419
    30 CLERK            950
    30 MANAGER         2850
    30 SALESMAN        1400
    30           1566.66666
       ANALYST         3000
       CLERK            674
       MANAGER   2758.33333
       PRESIDENT       5000
       SALESMAN        1400
                 1803.21428


3、使用GROUPIING函数
GROUPING函数用于确定统计结果是否用到了特定列。如果函数返回0,则表示统计结果使用了该列,如果函数返回1,则表示统计结果未使用该列。
SQL> SELECT deptno, job, avg(sal), grouping(deptno), grouping(job) FROM emp GROUP BY CUBE (deptno, job) ORDER BY deptno;

DEPTNO JOB         AVG(SAL) GROUPING(DEPTNO) GROUPING(JOB)
------ --------- ---------- ---------------- -------------
    10 CLERK           1300                0             0
    10 MANAGER         2450                0             0
    10 PRESIDENT       5000                0             0
    10           2916.66666                0             1
    20 ANALYST         3000                0             0
    20 CLERK     373.333333                0             0
    20 MANAGER         2975                0             0
    20                 1419                0             1
    30 CLERK            950                0             0
    30 MANAGER         2850                0             0
    30 SALESMAN        1400                0             0
    30           1566.66666                0             1
       ANALYST         3000                1             0
       CLERK            674                1             0
       MANAGER   2758.33333                1             0
       PRESIDENT       5000                1             0
       SALESMAN        1400                1             0
                 1803.21428                1             1


GROUPING SETS

使用GROUPING SETS操作符可以合并多个分组的结果。

1、显示部门平均工资

SQL> SELECT deptno, avg(sal) FROM emp GROUP BY deptno ORDER BY deptno;

DEPTNO   AVG(SAL)
------ ----------
    10 2916.66666
    20       1419
    30 1566.66666


2、显示岗位平均工资
SQL> SELECT job, avg(sal) FROM emp GROUP BY job ORDER BY avg(sal);

JOB         AVG(SAL)
--------- ----------
CLERK            674
SALESMAN        1400
MANAGER   2758.33333
ANALYST         3000
PRESIDENT       5000

3、显示部门平均工资和岗位平均工资
SQL> SELECT deptno, job, avg(sal) FROM emp GROUP BY GROUPING SETS(deptno, job) ORDER BY deptno, job;

DEPTNO JOB         AVG(SAL)
------ --------- ----------
    10           2916.66666
    20                 1419
    30           1566.66666
       ANALYST         3000
       CLERK            674
       MANAGER   2758.33333
       PRESIDENT       5000
       SALESMAN        1400


连接查询

连接查询是指基于两个或两个以上表或视图的查询。在使用连接查询时,应注意以下事项:
连接查询时,在FROM子句后指定两个或两个以上的表
连接查询时,如果在不同表之间存在同名列,那么在列名之前必须要加表名作为前缀。否则会因为列的二义性而报错
连接查询时,必须在WHERE子句中指定有效的连接条件(在不同表的列之间进行连接),如果不指定连接条件,或指定了无效的连接条件,那么会导致生成笛卡儿积(X*Y)。
连接查询时,使用表别名可以简化连接查询语句。

相等连接

相等连接是指使用“=”比较符指定连接条件的连接查询。这种连接查询主要用于检索主从表之间的相关数据。

使用相等连接执行主从查询,使用AND限定查询数据。
SQL> SELECT e.ename, d.dname FROM emp e, dept d WHERE e.deptno=d.deptno AND e.empno=7788;

ENAME      DNAME
---------- --------------
SCOTT      RESEARCH


不等连接

不等连接是指在连接条件中使用除相等比较符外的其它比较操作符的连接查询,并且不等连接主要用于在不同表之间显示特定范围的信息。
SQL> SELECT e.ename, e.sal, s.grade FROM emp e, salgrade s WHERE e.sal BETWEEN s.losal AND s.hisal AND e.deptno=10;

ENAME            SAL      GRADE
---------- --------- ----------
KING         5000.00          5
CLARK        2450.00          4
MILLER       1300.00          2


自连接

自连接是指在同一张表中的连接查询,也就是自己连接自己。它主要用在自参照表上显示上下级关系或者层次关系。自参照表是指在不同列之间具有参照关系或主从关系的表。因为自连接是在同一张表中连接,所以必须要定义别名,如,显示雇员BLAKE的上级领导为例:
SQL> SELECT manager.ename FROM emp manager, emp worker WHERE manager.empno=worker.mgr AND worker.ename='BLAKE';

ENAME
----------
KING

内连接和外连接

内连接用于返回满足连接条件的记录;外连接是内连接的扩展,不仅会返回满足连接条件的所有记录,而且还会返回不满足连接条件的记录。Oracle 9i之后连接语法既可以在WHERE子句中指定,也可以在FROM子句中指定。语法:SELECT table1.column, table2.column FROM table1 [INNER|LEFT|RIGHT|FULL] JOIN table2 ON table1.column1=table2.column2;

INNER JOIN表示内连接;LEFT JOIN表示左外连接;RIGHT JOIN表示右外连接;FULL JOIN表示完全外连接;ON子句用于指定连接条件。注意:如果使用FROM 子句指定内外连接,则必须要使用ON子句指定连接条件;如果使用(+)操作符指定外连接,则必须使用WHERE子句指定连接条件。

1、内连接
内连接用于返回满足连接条件的所有记录。默认情况下,在执行连接查询时没有指定任何连接操作符,那么这些连接查询都是属于内连接。
显示部门10的部门名及雇员名:
不带任何连接操作符的内连接
SQL> SELECT d.dname, e.ename FROM dept d, emp e WHERE d.deptno=e.deptno AND d.deptno=10;

DNAME          ENAME
-------------- ----------
ACCOUNTING     CLARK
ACCOUNTING     KING
ACCOUNTING     MILLER

在FROM子句中指定带INNER JOIN操作符的内连接
SQL> SELECT d.dname, e.ename FROM dept d INNER JOIN emp e ON d.deptno=e.deptno AND e.deptno=10;

DNAME          ENAME
-------------- ----------
ACCOUNTING     CLARK
ACCOUNTING     KING
ACCOUNTING     MILLER

此时的连接条件由关键字ON指定,不能由WHERE指定。

从Oracle 9i开始,如果主表的主键列和从表的外部键列名称相同,那么还可以使用NATURAL JOIN关键字自动执行内连接操作,如:
SQL> SELECT dname, ename FROM dept NATURAL JOIN emp;

DNAME          ENAME
-------------- ----------
ACCOUNTING     CLARK
ACCOUNTING     KING
ACCOUNTING     MILLER
RESEARCH       JONES
RESEARCH       FORD
RESEARCH       ADAMS
RESEARCH       SMITH
RESEARCH       SCOTT
SALES          WARD
SALES          TURNER
SALES          ALLEN
SALES          JAMES
SALES          BLAKE
SALES          MARTIN

2、左外连接
左外连接是通过指定LEFT [OUTER] JOIN选项来实现的。左外连接不仅会返回满足连接条件的所有记录,而且还会返回不满足连接条件的连接操作符左边表的其他行。如,显示部门10部门名、雇员名、以及其它部门名:
SQL> SELECT d.dname, e.ename FROM dept d LEFT JOIN emp e ON d.deptno=e.deptno AND
  2  d.deptno=10;

DNAME          ENAME
-------------- ----------
ACCOUNTING     CLARK
ACCOUNTING     KING
ACCOUNTING     MILLER
RESEARCH       
SALES          
OPERATIONS 

使用“+”操作符表示左外连接,左外连接不仅会返回满足连接条件的所有记录,而且还会返回不满足连接条件的连接操作符左边表的其他行,而(+)操作符要放在行数较少的一端,所以在WHERE子句中应该将该操作符放在右边表的一端。
SQL> SELECT d.dname, e.ename FROM dept d, emp e WHERE d.deptno=e.deptno(+) AND
  2  e.deptno(+)=10;

DNAME          ENAME
-------------- ----------
ACCOUNTING     CLARK
ACCOUNTING     MILLER
ACCOUNTING     KING
RESEARCH       
SALES          
OPERATIONS

3、右外连接
右外连接是使用RIGHT [OUTER] JOIN选项来实现的。不仅会返回满足条件的所有行,还会返回不满足条件的右边表的其它行。如,显示部门10的部门名、雇员名以及其它雇员名:
SQL> SELECT d.dname, e.ename FROM dept d RIGHT JOIN emp e ON d.deptno=e.deptno AND d.deptno=10;

DNAME          ENAME
-------------- ----------
ACCOUNTING     MILLER
ACCOUNTING     KING
ACCOUNTING     CLARK
               JAMES
               TURNER
               BLAKE
               MARTIN
               WARD
               ALLEN
               FORD
               ADAMS
               SCOTT
               JONES
               SMITH

使用“+”操作符表示右外连接,在WHERE子句中应该将该操作符放在左边表的一端
SQL> SELECT d.dname, e.ename FROM emp e, dept d WHERE d.deptno(+)=e.deptno AND d.deptno(+)=10;

DNAME          ENAME
-------------- ----------
ACCOUNTING     MILLER
ACCOUNTING     KING
ACCOUNTING     CLARK
               JAMES
               TURNER
               BLAKE
               MARTIN
               WARD
               ALLEN
               FORD
               ADAMS
               SCOTT
               JONES
               SMITH


4、完全外连接
完全外连接使用FULL [OUTER] JOIN选项指定。当使用完全外连接时,不仅会返回满足连接条件的所有行,而且还会返回不满足连接条件的所有行。如,显示部门10的部门名、雇员名以及其它部门名和雇员名为例:
SQL> SELECT d.dname, e.ename FROM dept d FULL JOIN emp e ON d.deptno=e.deptno AND d.deptno=10;

DNAME          ENAME
-------------- ----------
ACCOUNTING     CLARK
ACCOUNTING     KING
ACCOUNTING     MILLER
RESEARCH       
SALES          
OPERATIONS     
               SMITH
               ALLEN
               WARD
               JONES
               MARTIN
               BLAKE
               SCOTT
               TURNER
               ADAMS
               JAMES
               FORD


5、使用(+)操作符
在Oracle 9i之前,执行外连接都是使用(+)操作符,Oracle 9i开始Oracle建议使用OUTER JOIN执行外连接。当使用(+)操作符执行外连接时,应该将该操作符放在显示较少行(完全满足连接条件行)的一端。并且有以下注意事项:
  (+)操作符只能出现在WHERE子句中,且不能与OUTER JOIN语法同时使用
  (+)操作符执行外连接时,如果在WHERE子句中包含多个条件,则必须所有条件中都包含(+)操作符
  (+)操作符只适用于列,而不能用在表达式上
  (+)操作符不能与OR和IN操作符一起使用
  (+)操作符只能用于实现左外连接和右外连接


子查询

子查询是指嵌入在其它SQL语句中的SELECT语句,也称嵌套查询。根据子查询返回结果的不同,子查询又被分为单行子查询、多行子查询和多列子查询。

单行子查询

单行子查询是指只返回一行数据的子查询语句。 当在WHERE子句中引用单行子查询时,可以使用单行比较符(=、>、<、>=、<=、<>)。如,显示SCOTT的同事姓名、工资和部门号:
SQL> SELECT ename, sal, deptno FROM emp WHERE deptno=(SELECT deptno FROM emp WHERE ename='SCOTT');

ENAME            SAL DEPTNO
---------- --------- ------
SMITH          10.00     20
JONES        2975.00     20
SCOTT          10.00     20
ADAMS        1100.00     20
FORD         3000.00     20


多行子查询

多行子查询是指返回多行数据的子查询语句。当在WHERE子句中使用多行子查询时,必须要使用多行比较符(IN,ALL,ANY):
    ● IN:匹配于子查询结果的任一个值即可
    ALL:必须要符合子查询结果的所有值
    ANY:只要符合子查询结果的任一个值即可

注意,ALL和ANY操作符不能单独使用,而只能与单行比较符结合使用。

1、在多行子查询中使用IN操作符
显示匹配部门10岗位的雇员名、岗位、部门号:
SQL> SELECT ename, job, deptno FROM emp WHERE job IN(SELECT job FROM emp WHERE deptno=10);

ENAME      JOB       DEPTNO
---------- --------- ------
CLARK      MANAGER       10
BLAKE      MANAGER       30
JONES      MANAGER       20
KING       PRESIDENT     10
MILLER     CLERK         10
JAMES      CLERK         30
ADAMS      CLERK         20
SCOTT      CLERK         20
SMITH      CLERK         20

2、在多行子查询中使用ALL操作符
ALL操作符必须与单行比较符结合使用。如,高于部门30的所有雇员工资的雇员名、工资、部门号:
SQL> SELECT ename, sal, deptno FROM emp WHERE sal > ALL(SELECT sal FROM emp WHERE deptno=30);

ENAME            SAL DEPTNO
---------- --------- ------
JONES        2975.00     20
KING         5000.00     10
FORD         3000.00     20

3、在多行子查询中使用ANY操作符
ANY操作符也必须与单行比较符结合使用。如,显示高于部门30的任意雇员工资的雇员名、工资和部门号:
SQL> SELECT ename, sal, deptno FROM emp WHERE sal > ANY(SELECT sal FROM emp WHERE deptno=30);

ENAME            SAL DEPTNO
---------- --------- ------
KING         5000.00     10
FORD         3000.00     20
JONES        2975.00     20
BLAKE        2850.00     30
CLARK        2450.00     10
ALLEN        1600.00     30
TURNER       1500.00     30
MILLER       1300.00     10
WARD         1250.00     30
MARTIN       1250.00     30
ADAMS        1100.00     20

也就是大于部门30中最低工资。
SQL> SELECT ename, sal, deptno FROM emp WHERE sal > (SELECT min(sal) from emp WHERE deptno=30) ORDER BY sal DESC;

ENAME            SAL DEPTNO
---------- --------- ------
KING         5000.00     10
FORD         3000.00     20
JONES        2975.00     20
BLAKE        2850.00     30
CLARK        2450.00     10
ALLEN        1600.00     30
TURNER       1500.00     30
MILLER       1300.00     10
WARD         1250.00     30
MARTIN       1250.00     30
ADAMS        1100.00     20


多列子查询

单行子查询是指子查询只返回单列单行数据,多行子查询是指子查询返回单列多行数据,二者都是针对单列而言的。而多列子查询则是指返回多列数据的子查询语句。当多列子查询返回单行数据时,在WHERE子句中可以使用单行比较符;当多列子查询返回多行数据时,在WHERE子句中必须使用多行比较符(IN、ALL、ANY)。

显示与SMITH部门和岗位完全相同的雇员信息:
SQL> SELECT ename, job, deptno FROM emp WHERE (deptno, job)=
  2  (SELECT deptno, job FROM emp WHERE ename='SMITH');

ENAME      JOB       DEPTNO
---------- --------- ------
SMITH      CLERK         20
SCOTT      CLERK         20
ADAMS      CLERK         20

SQL> SELECT ename, job, deptno FROM emp WHERE (deptno, job) IN
  2  (SELECT deptno, job FROM emp WHERE ename='SMITH');

ENAME      JOB       DEPTNO
---------- --------- ------
ADAMS      CLERK         20
SCOTT      CLERK         20
SMITH      CLERK         20

在使用子查询比较多个列的数据时,既可以使用成对比较,也可以使用非成对比较。成对比较要求多个列的数据必须同时匹配。


其它子查询

1、相关子查询
相关子查询是指需要引用主查询表列的子查询语句,相关子查询是通过EXISTS谓词来实现的。如,显示在‘NEW YORK’的雇员信息:
SQL> SELECT ename, sal, job, deptno FROM emp WHERE EXISTS
  2  (SELECT 1 FROM dept WHERE dept.deptno=emp.deptno AND dept.loc='NEW YORK');

ENAME            SAL JOB       DEPTNO
---------- --------- --------- ------
CLARK        2450.00 MANAGER       10
KING         5000.00 PRESIDENT     10
MILLER       1300.00 CLERK         10

使用EXISTS谓词时,如果子查询存在返回结果,则返回TRUE,否则返回FALSE。

2、在FROM子句中使用子查询
当在FORM子句中使用子查询时,该子查询会被作为视图对待,因此也被称为内嵌视图。注意,在FROM子句中使用子查询时,必须要给子查询指定别名。
显示高于部门平均工资的雇员信息:
SQL> SELECT e.ename, e.sal, e.deptno, ee.avgsal FROM emp e,
  2  (SELECT deptno, avg(sal) avgsal FROM emp GROUP BY deptno) ee
  3  WHERE e.sal>ee.avgsal AND e.deptno=ee.deptno;

ENAME            SAL DEPTNO     AVGSAL
---------- --------- ------ ----------
ALLEN        1600.00     30 1566.66666
JONES        2975.00     20       1419
BLAKE        2850.00     30 1566.66666
KING         5000.00     10 2916.66666
FORD         3000.00     20       1419

3、在DML语句中使用子查询
在INSERT语句中使用子查询,可以将一张表的数据装载到另一张表中。
SQL> INSERT INTO employee SELECT * FROM emp WHERE deptno=20;

5 rows inserted

在UPDATE语句中使用子查询,即可以在WHERE子句中引用子查询(返回未知条件值),也可以在SET子句中使用子查询(修改列数据)。
将SMITH同岗位的雇员工资和补助更新为与SMITH的工资和补助一致:
SQL> UPDATE emp SET(sal, comm)=(SELECT sal, comm FROM emp WHERE ename='SMITH') 
  2  WHERE job=(SELECT job FROM emp WHERE ename='SMITH');

5 rows updated


在DELETE语句中使用子查询,可以在WHERE子句中引用子查询返回未知条件值。
SQL> DELETE FROM employee WHERE deptno=(SELECT deptno FROM dept WHERE dname='ACCOUNTING');

3 rows deleted

当在SELECT和DML语句中使用子查询时,WHERE子句和SET子句的子查询语句不能包含ORDER BY子句。但在DDL语句中使用子查询时,子查询可以包含ORDER BY子句。

4、在DDL语句中使用子查询
在CREATE TABLE中使用子查询,可以在建立新表的同时复制表中的数据。
SQL> CREATE TABLE employee AS SELECT * FROM emp WHERE deptno=10;

Table created


在CREATE VIEW中使用子查询,建立视图时,必须指定视图所对应的子查询语句。
SQL> CREATE OR REPLACE VIEW v_emp
  2  AS
  3  SELECT deptno, ename, sal, empno FROM SCOTT.emp
  4  WHERE deptno=10;

View created


在CREATE MATERIALIZED VIEW语句中使用子查询
SQL> CREATE MATERIALIZED VIEW v_emp
  2  AS
  3  SELECT deptno,job,avg(sal) avgsal,sum(sal) sumsal
  4  FROM SCOTT.emp GROUP BY cube(deptno, job);

Materialized view created

SQL> select * from v_emp;

DEPTNO JOB           AVGSAL     SUMSAL
------ --------- ---------- ----------
                 1803.21428      25245
       CLERK            674       3370
       ANALYST         3000       3000
       MANAGER   2758.33333       8275
       SALESMAN        1400       5600
       PRESIDENT       5000       5000
    10           2916.66666       8750
    10 CLERK           1300       1300
    10 MANAGER         2450       2450
    10 PRESIDENT       5000       5000
    20                 1419       7095
    20 CLERK     373.333333       1120
    20 ANALYST         3000       3000
    20 MANAGER         2975       2975
    30           1566.66666       9400
    30 CLERK            950        950
    30 MANAGER         2850       2850
    30 SALESMAN        1400       5600


合并查询

为了合并多个SELECT语句的结果,可以使用集合操作符UNION、UNION ALL、INTERSECT、MINUS。
语法:SELECT 语句1 [UNION | UNION ALL | INTERSECT | MINUS] SELECT 语句2;
当使用集合操作符时,必须确保不同查询的列个数和数据类型都要匹配。另外,使用集合操作还有以下一些限制:
      对于LOB、VARRAY和嵌套表列来说,集合操作符是无效的
      对于LONG列来说,UNION、INTERSECT、MINUS操作符是无效的
      如果选择列表包含了表达式,则必须要为其指定列别名

SQL> select sal,ename,job from emp where sal>2500;

      SAL ENAME      JOB
--------- ---------- ---------
  2975.00 JONES      MANAGER
  2850.00 BLAKE      MANAGER
  5000.00 KING       PRESIDENT
  3000.00 FORD       ANALYST

SQL> select sal,ename,job from emp where job='MANAGER';

      SAL ENAME      JOB
--------- ---------- ---------
  2975.00 JONES      MANAGER
  2850.00 BLAKE      MANAGER
  2450.00 CLARK      MANAGER


UNION

UNION操作符用于获取两个结果集的并集。当使用该操作符时,会自动除掉结果集中的重复行,并且会以第一列的结果进行排序
显示工资高于2500的雇员和岗位为‘MANAGER’的雇员:
SQL> SELECT sal, ename, job FROM emp WHERE sal>2500
  2  UNION
  3  SELECT sal, ename, job FROM emp WHERE job='MANAGER';

      SAL ENAME      JOB
--------- ---------- ---------
  2450.00 CLARK      MANAGER
  2850.00 BLAKE      MANAGER
  2975.00 JONES      MANAGER
  3000.00 FORD       ANALYST
  5000.00 KING       PRESIDENT


UNION ALL

用于获取两个结果集的并集,与UNION操作符不同的是,该操作符不会取消重复行而且也不会以任何列进行排序
SQL> SELECT sal, ename, job FROM emp WHERE sal>2500
  2  UNION ALL
  3  select sal,ename,job from emp where job='MANAGER';

      SAL ENAME      JOB
--------- ---------- ---------
  2975.00 JONES      MANAGER
  2850.00 BLAKE      MANAGER
  5000.00 KING       PRESIDENT
  3000.00 FORD       ANALYST
  2975.00 JONES      MANAGER
  2850.00 BLAKE      MANAGER
  2450.00 CLARK      MANAGER


INTERSECT

INTERSECT操作符用于获取两个结果集的交集。并且会以第一列进行排序。
SQL> SELECT sal, ename, job FROM emp WHERE sal>2500
  2  INTERSECT
  3  select sal,ename,job from emp where job='MANAGER';

      SAL ENAME      JOB
--------- ---------- ---------
  2850.00 BLAKE      MANAGER
  2975.00 JONES      MANAGER


MINUS

MINUS操作符用于获取两个结果集的差集。并且会以第一列进行排序。
SQL> SELECT sal, ename, job FROM emp WHERE sal>2500
  2  MINUS
  3  select sal,ename,job from emp where job='MANAGER';

      SAL ENAME      JOB
--------- ---------- ---------
  3000.00 FORD       ANALYST
  5000.00 KING       PRESIDENT



其它复杂查询

层次查询
SQL> col job format a15;
SQL> SELECT LPAD(' ', 3*(LEVEL-1)) || ename ename,
  2  LPAD(' ', 3*(LEVEL-1)) || job job FROM emp
  3  START WITH mgr IS NULL
  4  CONNECT BY mgr=PRIOR empno;

ENAME                                                                            JOB
-------------------------------------------------------------------------------- ---------------
KING                                                                             PRESIDENT
   JONES                                                                            MANAGER
      SCOTT                                                                            CLERK
         ADAMS                                                                            CLERK
      FORD                                                                             ANALYST
         SMITH                                                                            CLERK
   BLAKE                                                                            MANAGER
      ALLEN                                                                            SALESMAN
      WARD                                                                             SALESMAN
      MARTIN                                                                           SALESMAN
      TURNER                                                                           SALESMAN
      JAMES                                                                            CLERK
   CLARK                                                                            MANAGER
      MILLER                                                                           CLERK

14 rows selected

SQL> SELECT e.ename,ee.ename boss from emp e, emp ee WHERE ee.empno(+)=e.mgr;

ENAME      BOSS
---------- ----------
FORD       JONES
SCOTT      JONES
JAMES      BLAKE
TURNER     BLAKE
MARTIN     BLAKE
WARD       BLAKE
ALLEN      BLAKE
MILLER     CLARK
ADAMS      SCOTT
CLARK      KING
BLAKE      KING
JONES      KING
SMITH      FORD
KING      


使用CASE表达式

为了在SQL语句中使用IF…THEN…ELSE语法,可以使用CASE表达式。通过使用CASE表达式可以避免调用过程来完成分支操作。当使用CASE表达式时,使用WHEN子句可以指定条件语句。如,显示部门10雇员名、工资、工资级别:
SQL> SELECT e.ename, e.sal, s.grade FROM emp e, salgrade s
  2  WHERE e.sal BETWEEN s.losal AND s.hisal AND e.deptno=10;

ENAME            SAL      GRADE
---------- --------- ----------
KING         5000.00          5
CLARK        2450.00          4
MILLER       1300.00          2


SQL> SELECT ename, sal, CASE WHEN sal>3000 THEN 5
  2  WHEN sal BETWEEN 1200 AND 1400 THEN 2
  3  WHEN sal BETWEEN 2000 AND 3000 THEN 4
  4  WHEN sal BETWEEN 1400 AND 2000 THEN 3 
  5  ELSE 1 END grade
  6  FROM emp WHERE deptno=10;

ENAME            SAL      GRADE
---------- --------- ----------
CLARK        2450.00          4
KING         5000.00          5
MILLER       1300.00          2


倒叙查询

默认情况下,当执行查询操作时,只能看到最近提交的数据。从Oracle 9i开始通过使用倒叙(FLASHBACK QUERY)查询特征,可以查看到过去某时间点提交的数据。注意,如果使用倒叙查询,那么要求数据库必须采用UNDO管理方式,并且初始化参数undo_retention限制了UNDO数据的保留时间。
SQL> SELECT ename, sal FROM emp WHERE ename='SMITH';

ENAME            SAL
---------- ---------
SMITH        1000.00

SQL> SELECT ename, sal FROM emp AS OF TIMESTAMP to_timestamp(
  2  '2012-08-08 17:12:00', 'YYYY-MM-DD HH24:MI:SS') 
  3  WHERE ename='SMITH';

ENAME            SAL
---------- ---------
SMITH          10.00

执行倒叙查询时,通过在FROM子句后指定AS OF子句可以查看过去的历史数据,在AS OF子句中既可以指定时间,也可以指定SCN。注意,使用倒叙查询只能看到5分钟之前变化的数据,而不能查看到5分钟之内变化的数据。

使用WITH子句重用子查询

对于多次使用相同子查询的复杂查询语句来说,用户可能会将查询语句分成两条语句执行。第一条语句将子查询结果存放到临时表,第二条查询语句使用临时表处理数据。从Oracle 9i开始,通过WITH子句可以给子查询指定一个名称,并且使得在一条语句中可以完成所有任务,从而避免了使用临时表。如,显示部门工资总和高于雇员工资总和三分之一的部门名及工资总和:
SQL> SELECT dname,sum(sal) FROM emp,dept WHERE emp.deptno=dept.deptno
  2  GROUP BY dname HAVING sum(sal)>(SELECT sum(sal)*1/3 from emp);

DNAME            SUM(SAL)
-------------- ----------
ACCOUNTING           8750
SALES                9400

使用WITH子句

SQL> WITH summary AS (
  2  SELECT dname, sum(sal) sal_total FROM emp, dept 
  3  WHERE emp.deptno=dept.deptno GROUP BY dname
  4  )
  5  SELECT dname, sal_total FROM summary WHERE sal_total>
  6  (SELECT sum(sal_total)*1/3 FROM summary);

DNAME           SAL_TOTAL
-------------- ----------
ACCOUNTING           8750
SALES                9400

你可能感兴趣的:(使用SQL语句)