Oracle入门教程与实战

前言

Oracle 数据库系统是美国 Oracle 公司(甲骨文)提供的以分布式数据库为核心的一组软件产品,是目前最流行的客户/服务器 (Client/Server) 或 B/S 体系结构的数据库之一,比如 SilverStream 就是基于数据库的一种中间件。 Oracle 数据库是目前世界上使用最为广泛的数据库管理系统,作为一个通用的数据库系统,它具有完整的数据管理功能;作为一个关系型数据库,它是一个完备关系的产品;作为分布式数据库它实现了分布式处理功能,但它的所有知识,只要在一种机型上学习了 Oracle 知识,便能在各种类型的机器上使用它。

Oracle 的基本使用

连接命令

sqlplus /nolog

进入 sqlplus 环境。其中 /nolog 是不登陆到数据库服务器的意思,如果没有 /nolog 参数, sqlplus 会提示你输入用户名和密码。

C:\Users\Administrator>sqlplus

SQL*Plus: Release 11.1.0.7.0 - Production on 星期三 10月 16 10:30:42 2019

Copyright (c) 1982, 2008, Oracle.  All rights reserved.

请输入用户名:

conn[etc]

用法: conn 用户名 / 密码 @网络服务名 [as sysdba/sysoper] 当用特权用户身份连接时,必须带上 as sysdba 或是 as sysoper

以系统管理员 (sysdba) 身份连接数据库

SQL> conn / as sysdba
已连接。

创建用户

SQL> create user huang identified by 123456;

用户已创建。

用户授权

SQL> grant create session,connect,resource to huang;

授权成功。

连接到数据库

SQL> conn huang/123456
已连接。

show user

显示当前用户名

SQL> show user
USER 为 "HUANG"

passw[ord]

用于修改用户的密码,如果要想修改其它用户的密码,需要用 sys/system 登录。

SQL> passw
更改 HUANG 的口令
旧口令:
新口令:
重新键入新口令:
口令已更改

disc[onnect]

用于断开与当前数据库的连接 (不退出 sqlplus )

SQL> disc
从 Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options 断开
SQL>

exit

用于断开与当前数据库的连接 (同时退出 sqlplus )

SQL> exit
从 Oracle Database 11g Enterprise Edition Release 11.1.0.7.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options 断开

C:\Users\Administrator>

文件操作命令

start 和 @

运行 SQL 脚本

SQL> @ d:\c.sql

表已创建。

或是

SQL> start d:\c.sql

表已创建。

edit

该命令可以编辑指定的 SQL 脚本

SQL> edit d:\c.sql

这样会把 d:\c.sql 这个文件打开

spool

该命令可以将 sqlplus 屏幕上的(查询)内容输出到指定文件中去

SQL> spool d:\d.sql
SQL> select ASSETNUM 序号,DESCRIPTION 描述 from ASSET;
SQL> spool off

交互式命令

&

可以替代变量,而该变量在执行时,需要用户输入, Oracle 会提示用户输入值

SQL> select * from ACCOUNTDEFAULTS where ORGID='&ORGID';
输入 orgid 的值:

显示和设置环境变量

可以用来控制输出的各种格式,如果希望永久的保存相关设置,可以修改 glogin.sql 脚本

linesize

设置显示行的宽度,默认是 80 个字符

SQL> show linesize
linesize 80
SQL> set linesize 90
SQL> show linesize
linesize 90

pagelize

设置每页显示的行数目,默认是 14 ,用法和 linesize 一样

SQL> show pagesize
pagesize 14
SQL> set pagesize 20
SQL> show pagesize
pagesize 20

Oracle 用户管理

创建用户

在 Oracle 中要创建一个新的用户使用 create user 语句, 一般是具有 dba (数据库管理员)的权限才能使用。

create user 用户名 identified by 密码 ;
SQL> create user zhangsan identified by 123456;
create user zhangsan identified by 123456
                                   *
第 1 行出现错误:
ORA-01031: 权限不足

我们连接到 sysdba 创建用户

SQL> conn / as sysdba
已连接。
SQL> create user zhangsan identified by 123456;

用户已创建。

给用户修改密码

如果给自己修改密码可以直接使用

password 用户名
SQL> password huang
更改 huang 的口令
旧口令:
新口令:
重新键入新口令:
口令已更改

如果给别人修改密码则需要具有 dba 的权限,或是拥有 alter user 的系统权限

 alter user 用户名 identified by 新密码
SQL> alter user zhangsan identified by 12345678;

用户已更改。

删除用户

一般以 dba 的身份去删除某个用户, 如果用其它用户去删除用户则需要具有 drop user 的权限。

drop user 用户名 [cascade]
SQL> drop user zhangsan;

用户已删除。

如果要删除的用户,已经创建了表,那么就需要在删除的时候带一个参数 cascade ;

权限和角色

权限

创建的新用户是没有任何权限的, 甚至连登陆的数据库的权限都没有, 需要为其指定相应的权限;要使用有能力授权的用户,如 sys 、 system 。

权限包含系统权限和对象权限

  • 系统权限:用户对数据库的相关权限
  • 对象权限:用户对其他用户的数据对象操作的权限

角色

角色是指由系统权限集合。通常给某个用户授予权限时如果没有角色存在的话,那么需要一条一条的操作,角色的存在就是使得授权变得很方便。通常一个角色由多个系统权限组成。常用的角色有三个 connect (7种权限)、 dba 、 resource (在任何表空间建表)。

connect 角色:是授予最终用户的典型权利,最基本的

  • alter session 修改会话
  • create cluster 建立聚簇
  • create database link 建立数据库链接
  • create sequence 建立序列
  • create session 建立会话
  • create synonym 建立同义词
  • create view 建立视图

resource 角色: 是授予开发人员的

  • create cluster 建立聚簇
  • create procedure 建立过程
  • create sequence 建立序列
  • create table 建表
  • cteate trigger 建立触发器
  • create type 建立类型

dba 角色:拥有系统所有系统级权限

使用 grant 命令给用户分配权限:

grant 【权限名】 to 【用户名】

  • 分配角色
grant 【角色名】 to 【用户名】
  • 收回权限
revoke 【权限名】 from 【用户名】

用户管理的综合案例

SQL> create user zhangsan identified by 123456; /*创建用户*/

用户已创建。

SQL> conn zhangsan/123456; /*新建用户没有 session (登陆)权限*/
ERROR:
ORA-01045: 用户 ZHANGSAN 没有 CREATE SESSION 权限; 登录被拒绝


警告: 您不再连接到 ORACLE。
SQL> show user
USER 为 ""
SQL> conn / as sysdba;
已连接。
SQL> grant create session to zhangsan; /*使 zhangsan 能够被连接*/

授权成功。

SQL> conn zhangsan/123456;
已连接。
SQL> show user;
USER 为 "ZHANGSAN"
SQL> conn / as sysdba;
已连接。
SQL> grant resource to zhangsan; /*让zhangsan 能够在任何表空间下建表*/

授权成功。

SQL> create table users(name varchar(10),age number(3)); /*在 sys 角色下创建一个简单的表 users */

表已创建。

SQL> insert into users values('张三',22); /*插入数据*/

已创建 1 行。

SQL> insert into users values('李四',24);

已创建 1 行。

SQL> select * from users; /*查询*/

NAME                        AGE
-------------------- ----------
张三                         22
李四                         24

SQL> conn zhangsan/123456;
已连接。
SQL> select * from sys.users; /*新建的用户没有查询 sys 表的权限*/
select * from sys.users
                  *
第 1 行出现错误:
ORA-00942: 表或视图不存在


SQL> conn / as sysdba;
已连接。
SQL> grant select on users to zhangsan; /*登录到 sys 给 zhangsan 授权让 zhangsan 可以查看 sys 下的 users 表*/

授权成功。

SQL> conn zhangsan/123456;
已连接。
SQL> select * from sys.users; /* 登录到 zhangsan 下查看 users 表*/

NAME                        AGE
-------------------- ----------
张三                         22
王五                         24

SQL> update sys.users set name='张小三' where name='张三'; /*这时如果想要更新 sys.users 中的数据,会提示 "ORA-01031: 权限不足 " 。因为 sys 只给了 zhangsan 查看的权利,如果仍然想更新,要到 sys 下进行授权*/
update sys.users set name='张小三' where name='张三'
           *
第 1 行出现错误:
ORA-01031: 权限不足


SQL> conn / as sysdba
已连接。
SQL> grant update on users to zhangsan; /*登录到 sys 给 zhangsan 授权让 zhangsan 可以更新 sys 下的 users 表*/

授权成功。

SQL> conn zhangsan/123456;
已连接。
SQL> update sys.users set name='张小三' where name='张三';

已更新 1 行。

SQL> select * from sys.users;

NAME                        AGE
-------------------- ----------
张小三                       22
王五                         24

SQL> revoke resource from zhangsan; /*登陆到 sys 下回收 resource 权限*/

撤销成功。

SQL> revoke select on users from zhangsan; /*登陆到 sys 下回收 select 权限*/

撤销成功。

SQL> conn zhangsan/123456;
已连接。
SQL> select * from sys.users; /* 这时 sys 就不能再查询 sys.users 的数据了*/
select * from sys.users
                  *
第 1 行出现错误:
ORA-00942: 表或视图不存在


使用 profile 管理用户口令

profile 是口令限制,资源限制的命令集合。当建立数据库时, Oracle 会自动建立名称为 default 的 profile。当建立用户没有制定 profile 选项,那 Oracle 就会将 default 分配给用户。

帐号锁定

指定登录时最多可以输入密码的次数,也可以指定用户锁定的时间,以天为单位。一般用 dba 的身份去执行命令。

指定用户 huang 最多只能尝试三次登录,锁定时间为 2 天。

SQL> conn / as sysdba;
已连接。
SQL> create profile lock_account limit failed_login_attempts 3 password_lock_time 2;

配置文件已创建

SQL> alter user huang profile lock_account;

用户已更改。

按 CTRL + C 退出来验证账号锁定

C:\Users\Administrator>sqlplus

SQL*Plus: Release 11.1.0.7.0 - Production on 星期三 10月 30 11:13:48 2019

Copyright (c) 1982, 2008, Oracle.  All rights reserved.

请输入用户名:  huang
输入口令:
ERROR:
ORA-01017: 用户名/口令无效; 登录被拒绝


请输入用户名:  huang
输入口令:
ERROR:
ORA-01017: 用户名/口令无效; 登录被拒绝


请输入用户名:  huang
输入口令:
ERROR:
ORA-28000: 帐户已被锁定


SP2-0157: 在 3 次尝试之后无法连接到 ORACLE, 退出 SQL*Plus

账户解锁

SQL> alter user huang account unlock;

用户已更改。

SQL> conn huang;
输入口令:
已连接。

终止口令

为了让用户定期修改密码,可以使用终止口令的指令完成,同样这个命令也要 dba 身份来操作。

给 huang 创建一个 profile 文件,要求该用户每隔 10 天要修改登录密码,宽限期 2 天

SQL> create profile huang limit password_life_time 10 password_grace_time 2;

配置文件已创建

SQL> alter user huang profile huang;

用户已更改。

解锁方式同上

口令历史

如果希望用户在修改密码时,不能使用以前用过的密码,可以使用口令历史,这样 Oracle 就会将口令修改的信息存放在数据字典中,这样当用户修改密码时, Oracle 就会对新密码与就得进行对比,如果一样提示用户重新输入。

SQL> create profile password_history limit password_life_time 10 password_grace_time 2 password_reuse_time 10;

配置文件已创建

SQL> alter user huang profile password_history;

用户已更改。

SQL> alter user huang identified by 12345678;

用户已更改。

SQL> alter user huang identified by 12345678;
alter user huang identified by 12345678
*
第 1 行出现错误:
ORA-28007: 无法重新使用口令


password_reuse_time 10 表示 10 天后口令可重复使用。

删除 profile

SQL> drop profile password_history cascade;

配置文件已删除。

cascade 表示如果已经将 profile分 配给某个用户时,仍要删除 profile,就要加上 cascade。

Oracle 表的管理

表名和列的命名规则

  • 必须以字母开头
  • 长度不能超过 30 个字符
  • 不能使用 Oracle 的保留字
  • 只能使用如下字符 A-Z , a-z , 0-9 , $ , # 等

Oracle 支持的数据类型

字符型

char 定长,最长2000字符

例如: char(10) 存储内容为“小黄”时,前4个字符放‘小黄’,后六位由空格补齐

优点是:效率高,查询速率快。如身份证的字段可以设置成 char(18)

varchar2 变长最大 4000 字符( Oracle 推荐使用)

varchar2(10) 存储内容为“小黄”时, Oracle 分配 4 个字符

clob(character large object) 字符型大对象,最大 4G

数字类型

number 范围 -10 的 38 次方到 10 的 38 次方,可以是整数,也可以是小数

number(5,2) 表示一个小数有5位有效数字, 2 位是小数

例如:定义一个范围在 -999.99-999.99 的数字可以用 number(5,2),定义一个范围在 -99999-99999 可以用 number(5)

日期类型

date 包含年月日和时分秒

timestamp Oracle 对 date 类型的扩展,可以精确到毫秒。

图片类型

blob 二进制数据,可以存放图片,音频,视频最大 4G ,这个类型允许我们将大文件存储进数据库,但是一般在数据库里,存放的应该是这些文件的路径,如果对安全性有要求,可以将文件放入数据库(一般来讲,在真实项目中是不会把图片和声音真的往数据库里存放的)。

建表语句

建表

  • 学生表
create table student( /*表名*/
    id number(4), /*学号*/
    name varchar2(20), /*姓名*/
    sex char(2), /*性别*/
    birthday date, /*出生日期*/
    sal number(6,2) /*奖学金*/
    );


SQL> desc student; /*查看表结构*/
 名称                                      是否为空? 类型
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER(4)
 NAME                                               VARCHAR2(20 CHAR)
 SEX                                                CHAR(2 CHAR)
 BIRTHDAY                                           DATE
 SAL                                                NUMBER(6,2)

  • 班级表
create table class(
    c_id number(2),
    c_name varchar2(40)
    );


SQL> desc class;
 名称                                      是否为空? 类型
 ----------------------------------------- -------- ----------------------------
 C_ID                                               NUMBER(2)
 C_NAME                                             VARCHAR2(40 CHAR)


修改表

SQL> alter table student add (c_id number(2)); /*添加字段*/

表已更改。

SQL> alter table student modify (name varchar2(50)); /*修改字段的长度*/

表已更改。

SQL> alter table student modify (name char(20)); /*修改字段的类型(表中不能有数据)*/

表已更改。

SQL> alter table student rename column name to s_name; /*修改字段的名字(表中不能有数据)*/

表已更改。

SQL> alter table student drop column sex; /*删除一个字段(慎重使用)*/

表已更改。

SQL> rename student to stu; /*修改表的名字*/

表已重命名。

SQL> desc stu;
 名称                                      是否为空? 类型
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER(4)
 S_NAME                                             CHAR(20 CHAR)
 BIRTHDAY                                           DATE
 SAL                                                NUMBER(6,2)
 C_ID                                               NUMBER(2)

SQL> drop table stu; /*删除表*/

表已删除。

SQL> desc stu;
ERROR:
ORA-04043: 对象 stu 不存在


操作表

使用 student 表

SQL> insert into student values(1,'张三','男','01-1月-19',8888.88); /*添加数据,所有字段必须都插入, Oracle 中默认的日期格式‘DD-MON-YY’ (日-月-年)*/

已创建 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY
---------- ---------------------------------------- ---- --------------
       SAL
----------
         1 张三                                     男   01-1月 -19
   8888.88


SQL> set linesize 300; /*设置行的宽度,这样就好看多了*/
SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY              SAL
---------- ---------------------------------------- ---- -------------- ----------
         1 张三                                     男   01-1月 -19        8888.88

SQL> alter session set nls_date_format='YYYY-MM-DD'; /*修改日期的默认格式。注意,这种修改方法,只对当前会话有效。而不是当前的 sql*plus 窗口。即如果你这样修改之后,又使用 connect 命令以其他用户连接到数据库或者是连接到其他的数据库,则这个日期格式就失效了,又恢复到缺省的日期格式。要想永久改变日期输入格式是需要改注册表的,还有一个方法是使用函数。*/

会话已更改。

SQL> insert into student values(2,'李四','男','2019-01-02',8888.88);

已创建 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     男   2019-01-01    8888.88
         2 李四                                     男   2019-01-02    8888.88

SQL> insert into student(id,name) values(3,'王五'); /*插入部分字段,前提是未插入的字段允许为 null */

已创建 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     男   2019-01-01    8888.88
         2 李四                                     男   2019-01-02    8888.88
         3 王五

SQL> insert into student(id,name,sex) values(4,null,null); /*插入空值*/

已创建 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     男   2019-01-01    8888.88
         2 李四                                     男   2019-01-02    8888.88
         3 王五
         4

SQL> select * from student where name=null; /*查询 name 为空的一条记录,错误的做法*/

未选定行

SQL> select * from student where name is null; /*查询 name 为空的一条记录,正确的做法*/

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         4

SQL> select * from student where name is not null; /*查询 name 不为空的一条记录*/

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     男   2019-01-01    8888.88
         2 李四                                     男   2019-01-02    8888.88
         3 王五

SQL> update student set sex='女' where id='1'; /*修改一个字段*/

已更新 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     女   2019-01-01    8888.88
         2 李四                                     男   2019-01-02    8888.88
         3 王五
         4

SQL> update student set sex='女',name='李小四' where id='2'; /*修改多个字段*/

已更新 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     女   2019-01-01    8888.88
         2 李小四                                   女   2019-01-02    8888.88
         3 王五
         4

SQL> update student set name='赵六' where name is null; /*修改含有 null 值的字段*/

已更新 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     女   2019-01-01    8888.88
         2 李小四                                   女   2019-01-02    8888.88
         3 王五
         4 赵六

SQL> insert into student values(1,'张三','女','2019-01-01',8888.88); /*增加一条重复的记录*/

已创建 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     女   2019-01-01    8888.88
         2 李小四                                   女   2019-01-02    8888.88
         3 王五
         4 赵六
         1 张三                                     女   2019-01-01    8888.88

SQL> select distinct id,name from student; /*取消重复行,查询时在 select 后面加上 distinct 即可将重复数据略去*/

        ID NAME
---------- ----------------------------------------
         3 王五
         2 李小四
         1 张三
         4 赵六

SQL> delete from student where id='4'; /*删除数据,删除一条记录*/

已删除 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张三                                     女   2019-01-01    8888.88
         2 李小四                                   女   2019-01-02    8888.88
         3 王五
         1 张三                                     女   2019-01-01    8888.88

SQL> delete from student; /*删除所有记录,表结构还在,会记录日志,这种删除是可以恢复的,速度会稍慢*/

已删除4行。

SQL> select * from student;

未选定行

SQL> truncate table student; /*删除所有记录,表结构还在,不记录日记,所有这种删除无法找回数据,但是速度很快*/

表被截断。

SQL> desc student;
 名称                                      是否为空? 类型
 ----------------------------------------- -------- ----------------------------
 ID                                                 NUMBER(4)
 NAME                                               VARCHAR2(20 CHAR)
 SEX                                                CHAR(2 CHAR)
 BIRTHDAY                                           DATE
 SAL                                                NUMBER(6,2)

SQL>  drop table student; /*删除表的结构和数据*/

表已删除。

SQL> desc student;
ERROR:
ORA-04043: 对象 student 不存在


SQL> create table student( /*表名*/ /*恢复数据,用 delete from student 时数据可恢,使用 student 表*/
  2      id number(4), /*学号*/
  3      name varchar2(20), /*姓名*/
  4      sex char(2), /*性别*/
  5      birthday date, /*出生日期*/
  6      sal number(6,2) /*奖学金*/
  7      );

表已创建。

SQL> insert into student values(1,'张小三','女','2019-01-01',8888.88); /*插入数据*/

已创建 1 行。

SQL> insert into student values(2,'李小四','女','2019-01-01',8888.88);

已创建 1 行。

SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张小三                                   女   2019-01-01    8888.88
         2 李小四                                   女   2019-01-01    8888.88

SQL> savepoint sp; /*首先要设置一个保存点*/

保存点已创建。

SQL> delete from student; /*删除数据*/

已删除2行。

SQL> select * from student; /*查询验证数据是否被删掉*/

未选定行

SQL> rollback to sp; /*回滚数据*/

回退已完成。

SQL> select * from student; /*查询验证数据回滚是否成功,可以设置多个保存点,但是如果不做处理,新的保存点会默认覆盖前一个保存点*/

        ID NAME                                     SEX  BIRTHDAY          SAL
---------- ---------------------------------------- ---- ---------- ----------
         1 张小三                                   女   2019-01-01    8888.88
         2 李小四                                   女   2019-01-01    8888.88


Oracle 的基本查询

PL/SQL 软件中两个命令

SQL> clear /*清屏命令*/
SQL> set timing on; /*打开显示操作时间*/
SQL> select * from student;

        ID NAME                                     SEX  BIRTHDAY              SAL
---------- ---------------------------------------- ---- -------------- ----------
         1 张小三                                   女   01-1月 -19        8888.88
         2 李小四                                   女   01-1月 -19        8888.88

已用时间:  00: 00: 00.00 /*这里显示操作时间*/
SQL> set timing off; /*关闭操作时间*/
SQL>  select count(*) from student; /*查询所有记录数*/

  COUNT(*)
----------
         2


注意
Oracle 的字段不区分大小写,实体区分大小写。

表基本查询

scott 用户存在的几张表 ( emp , dept ),本次实例采用 emp 和 dept 表。

使用算术表达式

显示每个雇员的月收入

SQL> select ename "姓名",sal 月工资 from emp;

姓名                     月工资
-------------------- ----------
SMITH                       800
ALLEN                      1600
WARD                       1250
JONES                      2975
MARTIN                     1250
BLAKE                      2850
CLARK                      2450
SCOTT                      3000
KING                       5000
TURNER                     1500
ADAMS                      1100

姓名                     月工资
-------------------- ----------
JAMES                       950
FORD                       3000
MILLER                     1300

已选择14行。

显示每个雇员的年收入

SQL> select ename "姓名",sal * 12 as "年收入" from emp;

姓名                     年收入
-------------------- ----------
SMITH                      9600
ALLEN                     19200
WARD                      15000
JONES                     35700
MARTIN                    15000
BLAKE                     34200
CLARK                     29400
SCOTT                     36000
KING                      60000
TURNER                    18000
ADAMS                     13200

姓名                     年收入
-------------------- ----------
JAMES                     11400
FORD                      36000
MILLER                    15600

这里的中文最好用引号引上,尽量不要用中文。

如果计算表达式中有一个 null 值,那么计算结果就为 null ,如何处理 null 值?

SQL> select sal * 13 + nvl(comm,0) * 13 "年薪",ename,comm from emp;

      年薪 ENAME                      COMM
---------- -------------------- ----------
     10400 SMITH
     24700 ALLEN                       300
     22750 WARD                        500
     38675 JONES
     34450 MARTIN                     1400
     37050 BLAKE
     31850 CLARK
     39000 SCOTT
     65000 KING
     19500 TURNER                        0
     14300 ADAMS

      年薪 ENAME                      COMM
---------- -------------------- ----------
     12350 JAMES
     39000 FORD
     16900 MILLER

已选择14行。

nvl(comm,0) 的意思是:如果 comm 为 null ,那么按 0 计算,不是 0 按本身计算。

用 "||" 来连接字符串

SQL> select ename || ' is a ' || job from emp; /*这句话表示:姓名为 XX 是做 XX 工作的*/

ENAME||'ISA'||JOB
------------------------------------------------------------------------------------------------------
SMITH is a CLERK
ALLEN is a SALESMAN
WARD is a SALESMAN
JONES is a MANAGER
MARTIN is a SALESMAN
BLAKE is a MANAGER
CLARK is a MANAGER
SCOTT is a ANALYST
KING is a PRESIDENT
TURNER is a SALESMAN
ADAMS is a CLERK

ENAME||'ISA'||JOB
------------------------------------------------------------------------------------------------------
JAMES is a CLERK
FORD is a ANALYST
MILLER is a CLERK

已选择14行。

使用 where 字句

显示工资高于 3000 的员工

SQL> select ename,sal from emp where sal > 3000;

ENAME                       SAL
-------------------- ----------
KING                       5000

查找 1982-1-1 后入职的员工

SQL> select ename from emp where hiredate > '1982-1-1';

ENAME
--------------------
SCOTT
ADAMS
MILLER

查找工资在 2000-2500 之间的员工,并且显示员工的工资

SQL> select ename,sal from emp where sal >=2000 and sal <=2500;

ENAME                       SAL
-------------------- ----------
CLARK                      2450

使用 like 操作符

%:表示 0 到多个字符
_:表示任意单个字符

显示首字母为 S 的员工

SQL> select ename from emp where ename like 'S%';

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

显示第三个字母为大写 O 的所有员工的姓名和工资

SQL> select ename,sal from emp where ename like '__O%'; /*注意: 两个 _ 符号*/

ENAME                       SAL
-------------------- ----------
SCOTT                      3000

在 where 条件中使用 in

显示 empno 为 7844 , 7839 , 123 , 456 的雇员情况

SQL> select * from emp where empno in(7844,7839,123,456);

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7839 KING                 PRESIDENT                     1981-11-17       5000                    10
      7844 TURNER               SALESMAN                 7698 1981-09-08       1500          0         30

这种查询效率很高

使用 is null 操作符

显示没有上级的雇员情况

SQL> select * from emp where mgr is null;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7839 KING                 PRESIDENT                     1981-11-17       5000                    10

使用逻辑操作符号

查询工资高于 500 或者是岗位为 MANAGER 的雇员,同时还要满足他们的姓名首字母为大写的 J

SQL> select * from emp where (sal >500 or job='MANAGER') and ename like 'J%';

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7566 JONES                MANAGER                  7839 1981-04-02       2975                    20
      7900 JAMES                CLERK                    7698 1981-12-03        950                    30

这里的括号不可以忘记,否则条件就变了,因为 and 的优先级高于 or 。

使用 order by 子句

按照工资从高到低的顺序显示雇员和工资

SQL> select ename,sal from emp order by sal desc;

ENAME                       SAL
-------------------- ----------
KING                       5000
FORD                       3000
SCOTT                      3000
JONES                      2975
BLAKE                      2850
CLARK                      2450
ALLEN                      1600
TURNER                     1500
MILLER                     1300
WARD                       1250
MARTIN                     1250

ENAME                       SAL
-------------------- ----------
ADAMS                      1100
JAMES                       950
SMITH                       800

已选择14行。

desc 为降序, asc 为升序(默认)

照部门号升序而雇员工资降序排列(知道某和部门最高工资的员工和最低工资的员工是谁)

SQL> select * from emp order by deptno asc,sal desc;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7839 KING                 PRESIDENT                     1981-11-17       5000                    10
      7782 CLARK                MANAGER                  7839 1981-06-09       2450                    10
      7934 MILLER               CLERK                    7782 1982-01-23       1300                    10
      7788 SCOTT                ANALYST                  7566 1987-04-19       3000                    20
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20
      7566 JONES                MANAGER                  7839 1981-04-02       2975                    20
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20
      7369 SMITH                CLERK                    7902 1980-12-17        800                    20
      7698 BLAKE                MANAGER                  7839 1981-05-01       2850                    30
      7499 ALLEN                SALESMAN                 7698 1981-02-20       1600        300         30
      7844 TURNER               SALESMAN                 7698 1981-09-08       1500          0         30

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7654 MARTIN               SALESMAN                 7698 1981-09-28       1250       1400         30
      7521 WARD                 SALESMAN                 7698 1981-02-22       1250        500         30
      7900 JAMES                CLERK                    7698 1981-12-03        950                    30

已选择14行。

使用列的别名排序

SQL> select ename,sal * 12 "年薪" from emp order by "年薪" asc;

ENAME                      年薪
-------------------- ----------
SMITH                      9600
JAMES                     11400
ADAMS                     13200
WARD                      15000
MARTIN                    15000
MILLER                    15600
TURNER                    18000
ALLEN                     19200
CLARK                     29400
BLAKE                     34200
JONES                     35700

ENAME                      年薪
-------------------- ----------
SCOTT                     36000
FORD                      36000
KING                      60000

已选择14行。

Oracle 的复杂查询

在实际应用中经常需要执行复杂的数据统计,经常需要现实多张表的数据,所以经常要用到数据分组函数如 max() , min() , avg() , sum() , count() 等。

分组函数

显示所有员工中最高工资和最低工资

SQL> select max(sal),min(sal) from emp;

  MAX(SAL)   MIN(SAL)
---------- ----------
      5000        800

注意
如果列里面有一个分组函数,其它的都必须是分组函数, 否则就出错;如本例中不能写成:

SQL> select ename, sal from emp where sal = max(sal);
select ename, sal from emp where sal = max(sal)
                                       *
第 1 行出现错误:
ORA-00934: 此处不允许使用分组函数


因为: max 是分组函数,而 ename 不是分组函数。

查询最高,最低工资的员工(利用子查询)

SQL> select ename,sal from emp where sal = (select max(sal) from emp);

ENAME                       SAL
-------------------- ----------
KING                       5000

SQL> select ename,sal from emp where sal = (select min(sal) from emp);

ENAME                       SAL
-------------------- ----------
SMITH                       800

显示工资最高的员工的名字,工作岗位

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

ENAME                JOB
-------------------- ------------------
KING                 PRESIDENT

显示工资高于平均工资的员工信息

首先我们可以查询所有员工的平均工资

SQL> select avg(sal) from emp;

  AVG(SAL)
----------
2073.21429

然后再查询高于平均工资的员工信息

SQL> select * from emp where sal > 2073;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7566 JONES                MANAGER                  7839 1981-04-02       2975                    20
      7698 BLAKE                MANAGER                  7839 1981-05-01       2850                    30
      7782 CLARK                MANAGER                  7839 1981-06-09       2450                    10
      7788 SCOTT                ANALYST                  7566 1987-04-19       3000                    20
      7839 KING                 PRESIDENT                     1981-11-17       5000                    10
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20

已选择6行。

当然也可以利用子查询

SQL> select * from emp where sal > (select avg(sal) from emp);

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7566 JONES                MANAGER                  7839 1981-04-02       2975                    20
      7698 BLAKE                MANAGER                  7839 1981-05-01       2850                    30
      7782 CLARK                MANAGER                  7839 1981-06-09       2450                    10
      7788 SCOTT                ANALYST                  7566 1987-04-19       3000                    20
      7839 KING                 PRESIDENT                     1981-11-17       5000                    10
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20

已选择6行。

如果这里不是 * 号而是 ename,sal 等字段与分组函数那么在语句的最后要加上 group by ename,sal..(与 select 后的字段一致)

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

ENAME                       SAL
-------------------- ----------
JONES                      2975
SCOTT                      3000
KING                       5000
BLAKE                      2850
CLARK                      2450
FORD                       3000

已选择6行。

group by 和 having 子句

group by 用于对查询结果分组统计
having 子句用于限制分组显示结果

显示每个部门的平均工资和最高工资

SQL> select avg(sal),max(sal),deptno from emp group by deptno;

  AVG(SAL)   MAX(SAL)     DEPTNO
---------- ---------- ----------
1566.66667       2850         30
      2175       3000         20
2916.66667       5000         10

分组字段依据必须出现在查询结果中,否则结果可读性太差。

显示每个部门的每种岗位的平均工资和最低工资

SQL> select avg(sal),min(sal),deptno,job from emp group by job,deptno;

  AVG(SAL)   MIN(SAL)     DEPTNO JOB
---------- ---------- ---------- ------------------
      2975       2975         20 MANAGER
      5000       5000         10 PRESIDENT
      1300       1300         10 CLERK
      1400       1250         30 SALESMAN
      3000       3000         20 ANALYST
      2850       2850         30 MANAGER
      2450       2450         10 MANAGER
       950        950         30 CLERK
       950        800         20 CLERK

已选择9行。

显示平均工资低于 2000 的部门号和它的平均工资与最高工资

SQL> select avg(sal),max(sal),deptno from emp group by deptno having avg(sal) < 2000;

  AVG(SAL)   MAX(SAL)     DEPTNO
---------- ---------- ----------
1566.66667       2850         30

对分组函数的总结

  • 分组函数只能出现在选择列表, having , group by , order by 子句中
  • 如果在select语句中同时包含有 group by , having , order by ,那么顺序为 group by , having , order by
  • 在选择列中如果有列,表达式,和分组函数,那么这些列表达式必须有一个出现在 group by 子句中,否则出错 如:
select deptno,avg(sal),max(sal) from emp group by deptno having avg(sal) > 2000; /*这里的deptno就一定要出现在group by中*/

多表查询

基于两个或两个以上的表或是视图的查询,查单表满足不了要求,如部门和员工的关系。

SQL> select a.ename,a.sal,b.dname from emp a,dept b where a.deptno = b.deptno;

ENAME                       SAL DNAME
-------------------- ---------- ----------------------------
CLARK                      2450 ACCOUNTING
KING                       5000 ACCOUNTING
MILLER                     1300 ACCOUNTING
JONES                      2975 RESEARCH
FORD                       3000 RESEARCH
ADAMS                      1100 RESEARCH
SMITH                       800 RESEARCH
SCOTT                      3000 RESEARCH
WARD                       1250 SALES
TURNER                     1500 SALES
ALLEN                      1600 SALES

ENAME                       SAL DNAME
-------------------- ---------- ----------------------------
JAMES                       950 SALES
BLAKE                      2850 SALES
MARTIN                     1250 SALES

已选择14行。

如果不加 where 子句,就会产生笛卡尔集,所谓笛卡尔集,就是不加筛选,将所有的都查询出来。

结论:
两张表关联,至少需要一个条件排除笛卡尔集
三张表关联,至少需要二个条件排除笛卡尔集
以此类推:多表查询中,判断条件至少是表的个数 -1。

显示部门号为10的部门名,员工名和工资

SQL> select d.dname,e.ename,e.sal from emp e,dept d where e.deptno = d.deptno and d.deptno = 10;

DNAME                        ENAME                       SAL
---------------------------- -------------------- ----------
ACCOUNTING                   CLARK                      2450
ACCOUNTING                   KING                       5000
ACCOUNTING                   MILLER                     1300

显示各个员工的姓名,工资及工资的级别

SQL> select * from salgrade; /*先查看 salgrade 的表结构和记录*/

     GRADE      LOSAL      HISAL
---------- ---------- ----------
         1        700       1200
         2       1201       1400
         3       1401       2000
         4       2001       3000
         5       3001       9999

SQL> select e.ename,e.sal,s.grade from emp e,salgrade s where e.sal between s.losal and s.hisal;

ENAME                       SAL      GRADE
-------------------- ---------- ----------
SMITH                       800          1
JAMES                       950          1
ADAMS                      1100          1
WARD                       1250          2
MARTIN                     1250          2
MILLER                     1300          2
TURNER                     1500          3
ALLEN                      1600          3
CLARK                      2450          4
BLAKE                      2850          4
JONES                      2975          4

ENAME                       SAL      GRADE
-------------------- ---------- ----------
SCOTT                      3000          4
FORD                       3000          4
KING                       5000          5

已选择14行。

这里用到了 between ... and 子句,表示在 losal 和 hisal 之间。

显示雇员名,雇员工资及所在部门的名字,并部门排序

SQL> select e.ename,e.sal,d.dname from emp e,dept d where e.deptno = d.deptno order by e.deptno;

ENAME                       SAL DNAME
-------------------- ---------- ----------------------------
CLARK                      2450 ACCOUNTING
KING                       5000 ACCOUNTING
MILLER                     1300 ACCOUNTING
JONES                      2975 RESEARCH
FORD                       3000 RESEARCH
ADAMS                      1100 RESEARCH
SMITH                       800 RESEARCH
SCOTT                      3000 RESEARCH
WARD                       1250 SALES
TURNER                     1500 SALES
ALLEN                      1600 SALES

ENAME                       SAL DNAME
-------------------- ---------- ----------------------------
JAMES                       950 SALES
BLAKE                      2850 SALES
MARTIN                     1250 SALES

已选择14行。

如果用 group by ,一定要把 e.deptno 放到查询列里面。

自连接

自连接是指在同一张表的连接查询。

显示某个员工的上级领导的姓名

SQL> select worker.ename,boss.ename from emp worker,emp boss where worker.mgr = boss.empno and worker.ename = 'FORD';

ENAME                ENAME
-------------------- --------------------
FORD                 JONES

根据 FORD 的名字找到 FORD 的 mgr 编号再根据这个编号找到 boss 的 empno,最后显示出来。

子查询

子查询:指嵌入在其他 SQL 语句中的 select 语句,也叫做嵌套查询。

单行子查询

指只返回一行数据的子查询语句。

显示与 SMITH 同一部门的所有员工

分两步:

  1. 查出 SMITH 所在部门
  2. 根据部门查出所有员工
SQL> select deptno from emp where ename = 'SMITH';

    DEPTNO
----------
        20

SQL> select * from emp where deptno = (select deptno from emp where ename = 'SMITH');

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7369 SMITH                CLERK                    7902 1980-12-17        800                    20
      7566 JONES                MANAGER                  7839 1981-04-02       2975                    20
      7788 SCOTT                ANALYST                  7566 1987-04-19       3000                    20
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20

数据库在执行 SQL 是从左到右扫描的, 如果有括号的话,括号里面的先被优先执行。

多行子查询

返回多行数据的子查询

查询和部门 10 的工作相同的雇员的名字,岗位,工资,部门号

1.首先查出部门 10 的工作种类

SQL> select job from emp where deptno = 10;

JOB
------------------
MANAGER
PRESIDENT
CLERK

发现有重复结果,所以在 job 前加上 distinct

SQL> select distinct job from emp where deptno = 10;

JOB
------------------
CLERK
PRESIDENT
MANAGER

2.根据工作的种类查询

SQL> select ename,job,sal,deptno from emp where job in (select distinct job from emp where deptno = 10);

ENAME                JOB                       SAL     DEPTNO
-------------------- ------------------ ---------- ----------
CLARK                MANAGER                  2450         10
BLAKE                MANAGER                  2850         30
JONES                MANAGER                  2975         20
KING                 PRESIDENT                5000         10
MILLER               CLERK                    1300         10
JAMES                CLERK                     950         30
ADAMS                CLERK                    1100         20
SMITH                CLERK                     800         20

已选择8行。

注意这里 job 之后用的是" in "而非" = ",因为等号 = 是一对一的。

all 操作符

显示工资比部门 30 的所有员工的工资高的员工的姓名,工资和部门号

SQL> select ename,sal,deptno from emp where sal > all (select sal from emp where deptno = 30);

ENAME                       SAL     DEPTNO
-------------------- ---------- ----------
JONES                      2975         20
SCOTT                      3000         20
FORD                       3000         20
KING                       5000         10

也可以使用 max 方法

SQL> select ename,sal,deptno from emp where sal > (select max(sal) from emp where deptno = 30);

ENAME                       SAL     DEPTNO
-------------------- ---------- ----------
JONES                      2975         20
SCOTT                      3000         20
KING                       5000         10
FORD                       3000         20

max 方法的效率较高,原因是使用 all 操作符时,要和子查询所得结果逐一比较而使用 max 只需和 sal 中的最大值比较,减少了比较的次数,缩短了时间。数据量较大是会比较明显,数据量较小基本看不出来。

any 操作符

显示工资比部门 30 的任意一个员工的工资高的员工的姓名,工资和部门号

SQL> select ename,sal,deptno from emp where sal > any (select sal from emp where deptno = 30);

ENAME                       SAL     DEPTNO
-------------------- ---------- ----------
KING                       5000         10
FORD                       3000         20
SCOTT                      3000         20
JONES                      2975         20
BLAKE                      2850         30
CLARK                      2450         10
ALLEN                      1600         30
TURNER                     1500         30
MILLER                     1300         10
WARD                       1250         30
MARTIN                     1250         30

ENAME                       SAL     DEPTNO
-------------------- ---------- ----------
ADAMS                      1100         20

已选择12行。

也可以使用 min 方法

SQL> select ename,sal,deptno from emp where sal > (select min(sal) from emp where deptno = 30);

ENAME                       SAL     DEPTNO
-------------------- ---------- ----------
ALLEN                      1600         30
WARD                       1250         30
JONES                      2975         20
MARTIN                     1250         30
BLAKE                      2850         30
CLARK                      2450         10
SCOTT                      3000         20
KING                       5000         10
TURNER                     1500         30
ADAMS                      1100         20
FORD                       3000         20

ENAME                       SAL     DEPTNO
-------------------- ---------- ----------
MILLER                     1300         10

已选择12行。

原理同上

多列子查询

单行子查询是指子查询只返回单列、单行数据,多行子查询是指返回单列多行数据, 都是针对单列而言的,而多列子查询是指查询返回多个列数据的子查询语句。

查询与 SMITH 的部门和岗位完全相同的所有雇员

1.查询出 SMITH 的部门号,岗位

SQL> select deptno,job from emp where ename = 'SMITH';

    DEPTNO JOB
---------- ------------------
        20 CLERK

2.显示结果

SQL> select * from emp where (deptno,job) = (select deptno,job from emp where ename = 'SMITH');

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7369 SMITH                CLERK                    7902 1980-12-17        800                    20
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20

在 from 子句中使用子查询

显示高于自己部门的平均工资员工信息

1.查询各个部门的平均工资和部门号

SQL> select avg(sal),deptno from emp group by deptno;

  AVG(SAL)     DEPTNO
---------- ----------
1566.66667         30
      2175         20
2916.66667         10

2.把上面的查询看作是一张子表

SQL> select e.ename,e.deptno,e.sal,ds.mysal from emp e,(select deptno, avg(sal) mysal from emp group by deptno) ds where e.deptno = ds.deptno and e.sal > ds.mysal;

ENAME                    DEPTNO        SAL      MYSAL
-------------------- ---------- ---------- ----------
ALLEN                        30       1600 1566.66667
JONES                        20       2975       2175
BLAKE                        30       2850 1566.66667
SCOTT                        20       3000       2175
KING                         10       5000 2916.66667
FORD                         20       3000       2175

已选择6行。

将这两个表做关联查询,当在 from 子句中使用子查询时,该子查询会被作为一个视图来对待,因此叫做内嵌视图,当在 from 子句中使用子查询时,必须为子查询指定别名。

注意:别名不能用 as ,如:

SQL> select e.ename,e.deptno,e.sal,ds.mysal from emp e,(select deptno, avg(sal) mysal from emp group by deptno) as ds where e.deptno = ds.deptno and e.sal > ds.mysal;
select e.ename,e.deptno,e.sal,ds.mysal from emp e,(select deptno, avg(sal) mysal from emp group by deptno) as ds where e.deptno = ds.deptno and e.sal > ds.mysal
                                                                                                           *
第 1 行出现错误:
ORA-00933: SQL 命令未正确结束


在 ds 前不能加 as ,否则会报错 (给表取别名的时候,不能加 as ;但是给列取别名,是可以加 as 的)。

Oracle 的分页

Oracle 的分页一共有三种方式:

  1. 根据 rowid 来分(效率最好)

  2. 按分析函数来分(效率次之)

  3. 按 rownum 来分(效率最差)

下面最主要介绍第三种:按 rownum 来分

SQL> select * from (select a.*,rownum rn from (select * from emp) a where rownum <= 15) where rn > 10;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO         RN
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ---------- ----------
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20         11
      7900 JAMES                CLERK                    7698 1981-12-03        950                    30         12
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20         13
      7934 MILLER               CLERK                    7782 1982-01-23       1300                    10         14

已用时间:  00: 00: 00.02

这条语句是用来将 11-15 条记录提取出来,拆分这条语句:

1.将所有想要的结果查询出来

SQL> select * from emp;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7369 SMITH                CLERK                    7902 1980-12-17        800                    20
      7499 ALLEN                SALESMAN                 7698 1981-02-20       1600        300         30
      7521 WARD                 SALESMAN                 7698 1981-02-22       1250        500         30
      7566 JONES                MANAGER                  7839 1981-04-02       2975                    20
      7654 MARTIN               SALESMAN                 7698 1981-09-28       1250       1400         30
      7698 BLAKE                MANAGER                  7839 1981-05-01       2850                    30
      7782 CLARK                MANAGER                  7839 1981-06-09       2450                    10
      7788 SCOTT                ANALYST                  7566 1987-04-19       3000                    20
      7839 KING                 PRESIDENT                     1981-11-17       5000                    10
      7844 TURNER               SALESMAN                 7698 1981-09-08       1500          0         30
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ----------
      7900 JAMES                CLERK                    7698 1981-12-03        950                    30
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20
      7934 MILLER               CLERK                    7782 1982-01-23       1300                    10

已选择14行。

已用时间:  00: 00: 00.08

2.将上一步的结果作为一个视图,给每一条记录加上一个 rn 编号并将前 15 条记录查询出来;其中 rownum 为 Oracle 的关键字,且在第一次在查询字段中使用 rownum 时,如果有条件限制在 where 子句中也要用 rownum,不可以用 rn。

SQL> select a.*,rownum rn from (select * from emp) a where rownum <= 15;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO         RN
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ---------- ----------
      7369 SMITH                CLERK                    7902 1980-12-17        800                    20          1
      7499 ALLEN                SALESMAN                 7698 1981-02-20       1600        300         30          2
      7521 WARD                 SALESMAN                 7698 1981-02-22       1250        500         30          3
      7566 JONES                MANAGER                  7839 1981-04-02       2975                    20          4
      7654 MARTIN               SALESMAN                 7698 1981-09-28       1250       1400         30          5
      7698 BLAKE                MANAGER                  7839 1981-05-01       2850                    30          6
      7782 CLARK                MANAGER                  7839 1981-06-09       2450                    10          7
      7788 SCOTT                ANALYST                  7566 1987-04-19       3000                    20          8
      7839 KING                 PRESIDENT                     1981-11-17       5000                    10          9
      7844 TURNER               SALESMAN                 7698 1981-09-08       1500          0         30         10
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20         11

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO         RN
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ---------- ----------
      7900 JAMES                CLERK                    7698 1981-12-03        950                    30         12
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20         13
      7934 MILLER               CLERK                    7782 1982-01-23       1300                    10         14

已选择14行。

已用时间:  00: 00: 00.03

3.将前 15 条数据作为一个视图,提取出 11-15 条。

SQL> select * from (select a.*,rownum rn from (select * from emp) a where rownum <=15) where rn > 10;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO         RN
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ---------- ----------
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20         11
      7900 JAMES                CLERK                    7698 1981-12-03        950                    30         12
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20         13
      7934 MILLER               CLERK                    7782 1982-01-23       1300                    10         14

已用时间:  00: 00: 00.01

在 Java 程序中只需要替换 15 和 10 这两个数字就可以实现分页了。

用查询结果创建新表

这个命令是一种快捷的建表方法

SQL> select * from (select a.*,rownum rn from (select * from emp) a where rownum <=15) where rn > 10;

     EMPNO ENAME                JOB                       MGR HIREDATE          SAL       COMM     DEPTNO         RN
---------- -------------------- ------------------ ---------- ---------- ---------- ---------- ---------- ----------
      7876 ADAMS                CLERK                    7788 1987-05-23       1100                    20         11
      7900 JAMES                CLERK                    7698 1981-12-03        950                    30         12
      7902 FORD                 ANALYST                  7566 1981-12-03       3000                    20         13
      7934 MILLER               CLERK                    7782 1982-01-23       1300                    10         14

已用时间:  00: 00: 00.01
SQL> create table mytable(id,name,sal,job,deptno) as select empno,ename,sal,job,deptno from emp;

表已创建。

已用时间:  00: 00: 00.64

创建好之后,我们可以查看一下表结构

SQL> desc mytable;
 名称                                                  是否为空? 类型
 ----------------------------------------------------- -------- ------------------------------------
 ID                                                             NUMBER(4)
 NAME                                                           VARCHAR2(10)
 SAL                                                            NUMBER(7,2)
 JOB                                                            VARCHAR2(9)
 DEPTNO                                                         NUMBER(2)

SQL> desc emp;
 名称                                                  是否为空? 类型
 ----------------------------------------------------- -------- ------------------------------------
 EMPNO                                                 NOT NULL NUMBER(4)
 ENAME                                                          VARCHAR2(10)
 JOB                                                            VARCHAR2(9)
 MGR                                                            NUMBER(4)
 HIREDATE                                                       DATE
 SAL                                                            NUMBER(7,2)
 COMM                                                           NUMBER(7,2)
 DEPTNO                                                         NUMBER(2)

可以看出,新建表的字段类型和查询表的一样。

合并查询

有时在实际应用中,为了合并多个 select 语句的结果,可以使用集合操作符号 union, union all, intersect (交集), minus (差集)

多用于数据量比较大的数据局库,运行速度快。

union

该操作符用于取得两个结果集的并集。当使用该操作符时,会自动去掉结果集中重复行。

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

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

已选择6行。

已用时间:  00: 00: 00.00

union all

该操作符与 union 相似,但是它不会取消重复行,而且不会排序。

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

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

已选择8行。

已用时间:  00: 00: 00.01

intersect

使用该操作符用于取得两个结果集的交集。

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

ENAME                       SAL JOB
-------------------- ---------- ------------------
BLAKE                      2850 MANAGER
JONES                      2975 MANAGER

已用时间:  00: 00: 00.00

minus

使用改操作符用于取得两个结果集的差集, 他只会显示存在第一个集合中, 而不存在第二个集合中的数据。

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

ENAME                       SAL JOB
-------------------- ---------- ------------------
FORD                       3000 ANALYST
KING                       5000 PRESIDENT
SCOTT                      3000 ANALYST

已用时间:  00: 00: 00.00

集合操作要比 and, or 效率高很多。

操作数据

使用特定的格式插入日期值。

使用to_date函数

插入带有日期的表,并按照年月日格式插入

SQL> insert into emp values(9999,'huang','PERSIDENT',null,to_date('1997-01-01','YYYY-MM-DD'),800,1000,10);

已创建 1 行。

已用时间:  00: 00: 00.06

使用 to_date 函数可以插入任意形式的日期

使用子查询插入数据

一条 insert 语句可以插入大量的数据,当处理行迁移或者装载外部表的数据到数据库时, 可以使用子查询插入数据。

SQL> insert into mytable(id,name,deptno) select empno,ename,deptno from emp where deptno = 10;

已创建4行。

已用时间:  00: 00: 00.02
SQL> select * from mytable;

        ID NAME                        SAL JOB                    DEPTNO
---------- -------------------- ---------- ------------------ ----------
      7369 SMITH                       800 CLERK                      20
      7499 ALLEN                      1600 SALESMAN                   30
      7521 WARD                       1250 SALESMAN                   30
      7566 JONES                      2975 MANAGER                    20
      7654 MARTIN                     1250 SALESMAN                   30
      7698 BLAKE                      2850 MANAGER                    30
      7782 CLARK                      2450 MANAGER                    10
      7788 SCOTT                      3000 ANALYST                    20
      7839 KING                       5000 PRESIDENT                  10
      7844 TURNER                     1500 SALESMAN                   30
      7876 ADAMS                      1100 CLERK                      20

        ID NAME                        SAL JOB                    DEPTNO
---------- -------------------- ---------- ------------------ ----------
      7900 JAMES                       950 CLERK                      30
      7902 FORD                       3000 ANALYST                    20
      7934 MILLER                     1300 CLERK                      10
      7782 CLARK                                                      10
      7839 KING                                                       10
      7934 MILLER                                                     10
      9999 huang                                                      10

已选择18行。

已用时间:  00: 00: 00.02

后面 4 行为新插入的数据。

使用子查询更新数据

希望员工 huang 的岗位、工资与 SCOOT 一样

SQL> update mytable set(job,sal) = (select job,sal from mytable where name='SCOTT') where name = 'huang';

已更新 1 行。

已用时间:  00: 00: 00.00
SQL> select * from mytable;

        ID NAME                        SAL JOB                    DEPTNO
---------- -------------------- ---------- ------------------ ----------
      7369 SMITH                       800 CLERK                      20
      7499 ALLEN                      1600 SALESMAN                   30
      7521 WARD                       1250 SALESMAN                   30
      7566 JONES                      2975 MANAGER                    20
      7654 MARTIN                     1250 SALESMAN                   30
      7698 BLAKE                      2850 MANAGER                    30
      7782 CLARK                      2450 MANAGER                    10
      7788 SCOTT                      3000 ANALYST                    20
      7839 KING                       5000 PRESIDENT                  10
      7844 TURNER                     1500 SALESMAN                   30
      7876 ADAMS                      1100 CLERK                      20

        ID NAME                        SAL JOB                    DEPTNO
---------- -------------------- ---------- ------------------ ----------
      7900 JAMES                       950 CLERK                      30
      7902 FORD                       3000 ANALYST                    20
      7934 MILLER                     1300 CLERK                      10
      7782 CLARK                                                      10
      7839 KING                                                       10
      7934 MILLER                                                     10
      9999 huang                      3000 ANALYST                    10

已选择18行。

已用时间:  00: 00: 00.02

name 的值要用大写, Oracle 对值的大小写是敏感的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343