第四章 SQL 和 PL/SQL
-
Upload
ethan-ballard -
Category
Documents
-
view
94 -
download
0
description
Transcript of 第四章 SQL 和 PL/SQL
![Page 1: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/1.jpg)
第四章 SQL 和 PL/SQL
SQL
PL/SQL
![Page 2: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/2.jpg)
DDL 数据定义语言:包括一些支持定义或建立数据库对象(如表、索引、序列或视图)的语句。 Create 、 alter 、 drop
DML 数据操纵语言:包括允许对数据库进行处理或操纵的语句。 Select 、 insert 、 delete 、 update
![Page 3: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/3.jpg)
创建表
格式: create table 表名 ( 列名 1 数据类型 【约束】, 列名 2 数据类型 【约束】, 列名 3 数据类型 【约束】 ) ;
![Page 4: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/4.jpg)
数据类型 varchar2(size) 存放可变长字符数据 char(size) 存放定长字符数据 number(l,d) 存放数值型数据, l 代表总位
数, d 代表小数点后的位数 blob 二进制大对象 raw(size) 纯二进制数据 date 存放日期 long 存放可变长字符数据
![Page 5: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/5.jpg)
Number
number : 允许在小数点左边或右边输入任何个数的数字
Number(5) : 允许在小数点左边不多于 5 位数,如果任何数字被插入到小数点的右边,该数字将被 4 舍 5 入。
Number(5,2) :允许总数不超过 5 位数,其中2 位在小数点右边, 3 位在左边。
![Page 6: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/6.jpg)
约束 null/not null
primary key 要求进入该列的值是惟一的,且不为 null
foreign key
unique 防止重复值进入该列,但允许为 null
check 限制属性列的输入值
![Page 7: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/7.jpg)
命名约束与未命名约束
在建立或修改表时,用户可明确给出约束的名称。否则约束名将由 RDBMS 内部命名。由用户命名的约束称为命名约束; RDBMS 命名的约束由开发商决定,称未命名约束。
命名约束的格式: constraint 约束名 约束命名规定:表名-列名-后缀
![Page 8: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/8.jpg)
例 1 :用以下属性及设定建立表 calling-card.
属性:公司名 company-name 、卡号 card-number 、初值 starting-value 、余额 value-left 、初始密码 pin-number 。
设定:属性 company-name 可具有多达 25 个字符,属性 value-left 及 starting-value 用元及分来度量。属性 card-number 属性定义为主码;将 pin-number 属性定义为惟一码。
请用命名约束来书写 create table 。
![Page 9: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/9.jpg)
Create table calling-card
(company-name varchar2(25),
card-number varchar2(20) constraint
calling-card-card-number-pk primary key,
starting-value number(5,2),
value-left number(5,2),
pin-number char(12) constraint
calling-card-pin-number-u unique
);
![Page 10: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/10.jpg)
2. 描述表结构 当一个表建立后,可能需要确定表的名称、
数据类型及组成表的属性的一些约束。 使用: describe 表名; 或 desc 表名; 如: desc calling-card;
![Page 11: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/11.jpg)
3. 插入行
使用 insert into 语句,一条语句只允许一次插入一行。
insert into 表名(列 1 ,列 2 ,……列N )
values ( 值 1 ,值 2…… 值 N);
如果写在 values 子句中的数据项的顺序与create table 命令中表的属性顺序相同,则不用在 insert into 子句中写出列名。
![Page 12: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/12.jpg)
例 1 :将下列数据插入 calling-card 表移动 1237096435 50.00 12.45 987234569871联通 5497443544 100.00 11.37 433809835833
Insert into calling-card(company-name,card-number,starting-value,value-left,pin-number)
values(‘ 移动’,‘ 1237096435’ , 15.00 ,11.37 ,‘ 987234569871’) ;
Insert into calling-card(company-name,card-number,starting-value,value-left,pin-number)
values(‘ 联通 ’,‘ 5497443544’ , 100.00 ,11.37 ,‘ 433809835833’) ;
注:所有的字符数据都放再单引号内。
![Page 13: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/13.jpg)
练习 1 :利用下面给出的信息,写出 programmer 表的create table 指令。假设该表的属性满足下面所示的条件。
属性名 描述 / 数据类型 / 约束Empno 程序员的惟一 id ,最长为 3 个字符Project 程序员所参与的项目,最长为 3 个字符Taskno 该项目相关的任务号,为数值列,最多 2
位数name 雇员的姓名,最长为 25 个字符Hire-date 雇员的雇佣日期,日期数据类型Language 程序员使用的编程语言,最长 15 个字符
![Page 14: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/14.jpg)
Drop table programmer cascade constraints;
Create table programmer
(empno varchar2(3) primary key,
name varchar2(25) not null,
hiredate date,
project varchar2(3),
language varchar2(15),
taskno number(2)
);
![Page 15: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/15.jpg)
用下列数据填充 programmer 表。
empno Name hiredate project Language Taskno
201 John 1/1/95 NPR VB 52
789 richard 08/31/98 RNC JAVA 11
134 Andy 08/15/94 NITTS C++ 89
![Page 16: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/16.jpg)
Insert into programmer (empno,name,hire- date,project,language,tashno)
values(‘201’,’John’,’1-JAN-95’,’NPR’,’VB’,52);
注:在缺省设置中日期表示形式为:“ DD-MM-YY”, 其中 DD 是某月的任一天( 1 ~31 ), MM 是月份的前三个字母的缩写( JAN,FEB,DEC… ) ,YY 是年的后两位数字。
![Page 17: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/17.jpg)
练习 2 :写一个脚本,为零售店 Waves-R-US 建立一个产品表 product 。该表属性如下所示。如果需要的话可使用命令约束,并证实建立的表是正确的。
属性名 说明ID 惟一的产品标识,最长为 5 个字符。需要
Name 产品名,最长为 25 个字符。需要
Discount precentage
对优选客户的价格折扣百分率,最多 1 位数
Price 产品的零售价,总共 6 位数字,其中带 2 位小数
![Page 18: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/18.jpg)
Create table product
( id varchar2(5) constraint product-id-pk primary key,
Name varchar2(25)
constraint product-name-nn not null,
Discount-precentage number(1),
Price number(6,2)
) ;为了证实所建立的表是正确的,需要使用
describe product 命令确定它的结构。Describe product;
![Page 19: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/19.jpg)
4.Commit 及 rollback 命令 对一个表进行 insert 、 update 或 delete 操作后,用户可使用 commit 语句使所做的变更永久性的记录到数据库中。
一般大部分数据库处理完一个 DDL 语句后发出一个隐式的 commit 语句。
假设对表的改变(插入、更新或删除)尚未提交,用户可通过 rollback 语句取消对表所做的全部中间变化。
![Page 20: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/20.jpg)
Savepoint 命令
用户希望及时回到某一个特定点(称为保留点),取消保留点之后对表的改变可使用 savepoint 命令。
savepoint 保留点名; rollback 保留点名 或 rollback to savepoint 保留点名
![Page 21: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/21.jpg)
A B C
a1 b1 c1
a2 b2 c2
A B C
a1 b1 c1
a2 b2 c2
a3 b3 c3
Savepoint A Savepoint B
在表中插入一行
A B C
a2 b2 c2
a3 b3 c3
在表中删除第一行
Savepoint C
Rollback to savepoint A
![Page 22: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/22.jpg)
5.select 语句 select 列 1 ,列 2…… 列 N from 表 1 ,……表 N 【 where 条件】 【 order by 列 1[asc|desc][ 列 2[asc|desc]
…] 】 ;
Where 子句的比较运算符:=, <>, <, <=, > , >=查询表中所有列信息: select * from 表名;
![Page 23: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/23.jpg)
例 1 :使用 calling-card 表查询移动公司发行的电话卡的卡号和初值。查询显示按卡号从小到大排列。
select card-number, starting-value
from calling-card
where company-name=‘ 移动’ order by card-number [asc] ;
![Page 24: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/24.jpg)
练习 1 :1. 使用 employee 表显示在会计部门工作的
所有雇员的姓名及职务。
2.按雇员姓名的字母顺序显示上一个查询结果。
ID NAME DEPT TITLE
100 Smith Sales Clerk
200 John Marketing Clerk
300 Martin Accounting Clerk
400 Bell Accounting Sr.accountant
![Page 25: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/25.jpg)
1. Select name, title
from employee
where dept=‘Accounting’;
2. Select name, title
from employee
where dept=‘Accounting’
order by name;
![Page 26: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/26.jpg)
表行的更新update 表命令
Update 表名 set 列 1=新值 1 ,……列 N=新值
N
where 条件;
![Page 27: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/27.jpg)
例 1 :将卡号为 1237096435 的电话卡的公司名改为联通。
update calling-card
set company-name=‘ 联通’ where card-number=‘1237096435’;
![Page 28: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/28.jpg)
Delete 命令Delete from 表名
where 条件;…………删除指定行
Delete 表名; …………删除表中所有数据
例 1 :删除 calling-card 表中联通的所有电话卡记录。
Delete from calling-card where company-name=‘ 联通’ ;
![Page 29: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/29.jpg)
Drop table 命令Drop table 命令可从数据库中删除一个表及其中所有数据。
drop table 表名 【 cascade constraints 】 ;
如果想要删除的某个表具有参照完整性约束时,使用可选的 cascade constraints 子句。
![Page 30: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/30.jpg)
练习 1 : 写一个脚本,创建一个 emp 表,该表的属性如下:
列名 描述 / 数据类型Id 每个雇员惟一的标识号,最长为 3 个字符Name 雇员的姓名,最长为 20 个字符Userid 雇员登陆系统的 ID ,最长为 8 个字符Start-date 雇员开始在公司工作的日期Manager-id 雇员经理的 ID ,最长为 3 个字符Title 雇员在公司里的职务,最长为 25 个字符Dept-id 雇员的部门 ID ,最长为 3 个字符Salary 雇员的工资,共 11 位数,包括 2 位小数Commision 雇员赢得的佣金百分率,共 4 位数,包括 2 位小
数
![Page 31: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/31.jpg)
1.根据 emp 表,列出所有雇员的姓名、 ID及职务 , 要求不同职务按字母顺序排列,对相同职务的雇员,按其姓名的降序排列。
2. 给在部门 41工作的所有雇员提高工资 200 元。对结果加以验证。万一出错,确保所有的变化均能取消。如果操作有误,用户如何取消这些变化。
![Page 32: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/32.jpg)
1. Select name, id,title From emp Order by title , name desc;2. Savepoint before_update; update emp set salary=salary+200 where dept_id=’41’;通过查询可对改变是否正确加以验证: select name salary from emp where dept_id=’41’;如果更新不正确,用户可通过以下命令取消这些改变。 rollback to savepoint before_update;
![Page 33: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/33.jpg)
SQL 中关系运算符的执行使用 distinct取消重复的行
select [all|distinct] 列 1 ,列 2…… 列 N from 表 1 ,……表 N 【 where 条件】 【 order by 列 1[asc|desc][ 列 2[asc|desc]…] 】 ;
例:在 emp 表中,有多少不同的职务? select distinct title from emp;
![Page 34: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/34.jpg)
连接运算符的执行 连接( join )运算允许我们将来自两个或多
个表的数据形成一个单一表。主要的连接类型: 等值连接:两表通过共同的等值列而连接 自连接:一个表与其本身的连接 外连接:两个表之间的连接,决定一个表的
所有行在另一表中没有匹配的元组。
![Page 35: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/35.jpg)
等值连接 select 表 1. 列 1 ,表 1. 列 2…, 表 2. 列 1 ,…
表 2. 列 N
from 表 1 ,表 2
where 表 1. 列名=表 2. 列名;
如果在两个表中没有相同的列,则没有必要在列名前加表名。
![Page 36: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/36.jpg)
Emp 表:列名 描述 / 数据类型
Id 每个雇员惟一的标识号,最长为 3 个字符Name 雇员的姓名,最长为 20 个字符Userid 雇员登陆系统的 ID ,最长为 8 个字符Start-date 雇员开始在公司工作的日期Manager-id 雇员经理的 ID ,最长为 3 个字符Title 雇员在公司里的职务,最长为 25 个字符Dept-id 雇员的部门 ID ,最长为 3 个字符Salary 雇员的工资,共 11 位数,包括 2 位小数Commision 雇员赢得的佣金百分率,共 4 位数,包括 2 位小
数
![Page 37: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/37.jpg)
Dept 表:
列名 描述 / 数据类型
Id 每个部门惟一的标识号,最长为 3 个字符
Name 部门名称,最长为 20 个字符
Region_id 部门所在的区域 id ,最长为 3 个字符
![Page 38: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/38.jpg)
例 1 :查询所有雇员的姓名及所在部门名称。 Select emp.name,dept.name
From emp,dept
Where emp.dept_id=dept.id ;使用表别名: select A.name , B.name
from emp A,dept B
where A.dept_id=B.id ;
![Page 39: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/39.jpg)
自连接自连接是一个表与其自身的连接
例 1 :显示每一个雇员的名字及他或她的管理者的名字。
select E.name as “employee”,
M.name as “manager”
from emp E,emp M
where M.id=E.manager_Id
![Page 40: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/40.jpg)
外连接假设有两个表的连接,有时我们想知道不满足其中一个表指定条件的另一个表的行。例如,我们想知道还没有管理者的雇员。
select 表 1. 列 1 ,表 1. 列 2…, 表 2. 列 1 ,…表 2. 列 N
from 表 1 ,表 2
where 表 1. 列名(+)=表 2. 列名; 用于计算在表 1 中所有与表 2 不匹配的行的外连接 select 表 1. 列 1 ,表 1. 列 2…, 表 2. 列 1 ,…表 2. 列 N
from 表 1 ,表 2
where 表 1. 列名=表 2. 列名(+); 用于计算在表 2 中所有与表 1 不匹配的行的外连接
![Page 41: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/41.jpg)
例:列出无管理者的所有雇员。 select E.name as “employee”,
M.name as “manager”
from emp E,emp M
where M.id (+) =E.manager_Id
![Page 42: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/42.jpg)
练习 1 :1. 在 dept 表和 region 表中查询所有部门及它们所在的区域名。
2.显示所有销售代表及他们的客户的姓名。3.显示目前还没有指定销售代表的客户。
![Page 43: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/43.jpg)
Customer 表:
列名 描述 / 数据类型Id 客户惟一的标识号,最长为 3 个字符Name 客户名,最长为 20 个字符Address 客户的地址,最长为 20 个字符Zip_code 客户的邮政编码,最长为 15 个字符Phone 客户的电话号码,最长为 20 个字符Credit_rating 客户的信誉等级,最长为 9 个字符Sales_rep_id 客户的销售代表,最长为 3 个字符Region_id 客户居住的国家所在的区域,最长为
3 个字符
![Page 44: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/44.jpg)
Emp 表:列名 描述 / 数据类型
Id 每个雇员惟一的标识号,最长为 3 个字符Name 雇员的姓名,最长为 20 个字符Userid 雇员登陆系统的 ID ,最长为 8 个字符Start-date 雇员开始在公司工作的日期Manager-id 雇员经理的 ID ,最长为 3 个字符Title 雇员在公司里的职务,最长为 25 个字符Dept-id 雇员的部门 ID ,最长为 3 个字符Salary 雇员的工资,共 11 位数,包括 2 位小数Commision 雇员赢得的佣金百分率,共 4 位数,包括 2 位小
数
![Page 45: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/45.jpg)
1. Select D.name as “department” ,R.name as “region”
from dept D, region R where D.region_id = R.id ;2. Select E.name as “sales reps”, C.name as “customers” from emp E, customer C where C.sales_rep_id=E.id ;3. Select C.name as “customers” , E.name
as “sales reps” from emp E, customer C where C.sales_rep_id=E.id(+) ;
![Page 46: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/46.jpg)
建立外码create table 表名 ( 列名 1 数据类型 【 constraint 约束
名】 references 参照表名(列名), 列名 2 数据类型 【约束】, 列名 3 数据类型 【约束】 ) ;
![Page 47: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/47.jpg)
Emp 表:列名 描述 / 数据类型
Id 每个雇员惟一的标识号,最长为 3 个字符Name 雇员的姓名,最长为 20 个字符Userid 雇员登陆系统的 ID ,最长为 8 个字符Start-date 雇员开始在公司工作的日期Manager-id 雇员经理的 ID ,最长为 3 个字符Title 雇员在公司里的职务,最长为 25 个字符Dept-id 雇员的部门 ID ,最长为 3 个字符Salary 雇员的工资,共 11 位数,包括 2 位小数Commision 雇员赢得的佣金百分率,共 4 位数,包括 2 位小
数
![Page 48: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/48.jpg)
Dept 表:列名 描述 / 数据类型
Id 每个部门惟一的标识号,最长为 3 个字符
Name 部门名称,最长为 20 个字符
Region_id 部门所在的区域 id ,最长为 3 个字符
例 1 :根据上面的信息,建立 emp 表。定义dept_Id 为 FK, 且该 FK 参照另一个 dept 表的 id 。
![Page 49: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/49.jpg)
Create table emp( id varchar2(3) , name varchar2(20) , userid varchar2(8) , start_date date, manager_id varchar2(3), title varchar2(25), dept_id varchar2(3) references dept(id), salary number(11,2) commision number(4,2)) ;在加上外码约束时,必须确定 dept 表中属性 id已经被
定义为 PK 。
![Page 50: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/50.jpg)
在一个已存在的表中定义外码使用 alter table 命令:
alter table 表名 add 【 constraint 约束名】 foreign key( 列
名 )
references 参照表名(列名);
![Page 51: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/51.jpg)
例:使用 dept 表,将一个 FK加至此表中,使属性 region_id 参照 region 表的属性 id 。
Region 表:
alter table dept
add foreign key(region_id)
references region(id);
列名 描述 / 数据类型Id 每个区域惟一的标志号,最长为 3 个字符Name 每个区域惟一的名称,最长为 20 个字符
![Page 52: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/52.jpg)
在一个已存在的表中定义主码
使用 alter table 命令:
alter table 表名 add 【 constraint 约束名】 primary key( 列 1 [ ,列 2…] );
![Page 53: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/53.jpg)
例:在 dept 表中, id 及 region_id 的组合必须是惟一的。这一点确保了在地区中部门的惟一性。
alter table dept
add primary key (id, region_id);
![Page 54: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/54.jpg)
使用 check 约束限制属性列的输入值
![Page 55: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/55.jpg)
例:在 customer 表中,客户的信誉等级只能取excellent 、 good 或 poor 值。
create table customer
(id varchar2(3),
name varchar2(20),
address varchar2(20),
zip_code varchar2(15),
phone varchar2(20),
credit_rating varchar2(9) constraint customer_credit_rating_ck check(credit_rating IN (‘excellent’,’good’,’poor’)),
sales_rep_id varchar2(3),
region_id varchar2(3)
) ;
![Page 56: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/56.jpg)
例 2 :假设我们正在建立一个 department 表,其中,部门数大于 10 ,小于 50 。写出check 约束,以确保插入表中的每个部门数都在这个范围内。
create table department(
name varchar2(15)
constraint department_name_nn not null,
location varchar2(20),
deptnum number check (deptnum
between 10 and 50 ));
![Page 57: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/57.jpg)
对已存在的表添加属性列Alter table 表名
add 新列名 数据类型【约束】;
例 1 :在 department 表中,加入一个名为manager_name 的新列。假设该列可长达 25 个字符。
alter table department
add manager_name varchar2(25);
![Page 58: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/58.jpg)
对已存在的表修改属性列Alter table 表名
modify 列名 【数据类型 / 约束】 ;
例 1 :在 department 表中,增加 name 列大小。
alter table department
modify name varchar2(45);
![Page 59: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/59.jpg)
从表中删除约束
Alter table 表名 drop primary key 【 cascade 】 ;
Alter table 表名 drop unique 【 cascade 】 ;
Alter table 表名 drop 约束名【 cascade 】 ;
![Page 60: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/60.jpg)
从表中删除列
Alter table 表名 drop column 列名 ;
![Page 61: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/61.jpg)
例 1 :删除 department 表中 name 属性的not null 约束。
alter table department
drop constraint department_name_nn;
![Page 62: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/62.jpg)
练习:1. 将新列 performance加至 emp 表。该列的
允许值为‘ satisfactory’ ’、 excellent’ ’、 unsatisfactory’ 。证实该列被正确地加入了。
2. 将 customer 表中的属性 address 长度从 20个字符增加到 25 个字符。
3. 删除添加到 emp 表中的 check 约束。
![Page 63: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/63.jpg)
1. Alter table emp
add performance varchar2(15) constraint emp_performance_ck check ( performance in (‘satisfactory’,’excellent’,’unsatisfactory’));
2. Alter table customer
modify address varchar2(25 ) ;
3. Alter table emp
drop constraint emp_performance_ck;
![Page 64: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/64.jpg)
布尔运算符和字符匹配
1.布尔运算符:AND逻辑运算符
select 列名 from 表名 where 条件 1 AND 条件 2 ;
![Page 65: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/65.jpg)
例:列出 customer 表中具有 excellent 信誉等级、邮政编码为 22809 的所有客户的名称。
select name
from customer
where credit_rating=‘excellect’ and zip_code=‘22809’
/
![Page 66: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/66.jpg)
OR逻辑运算符 select 列名 from 表名 where 条件 1 OR 条件 2 ;
例:列出 customer 表中具有 excellent 或good 信誉等级的所有客户。Select nameFrom customerWhere credit_rating=‘excellect’ or credit_rating=‘good’/
![Page 67: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/67.jpg)
NOT逻辑运算符 select 列名 from 表名 where NOT 条件;
例:列出 customer 表中邮政编码不为 22808的全部客户名、邮政编码及销售代表号。
Select name, zip_code, sales_rep_idFrom customerWhere not zip_code=‘22808’/
![Page 68: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/68.jpg)
德 .摩根定律NOT(p AND q) NOT p OR NOT q
NOT(p OR q) NOT p AND NOT q
NOT(NOT p) p
例:列出 customer 表中邮政编码不为 22808 同时也不与 sales_rep_id 为 14 相关的销售代表相关的所有客户名、邮政编码及销售代表。
![Page 69: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/69.jpg)
Select name, zip_code, sales_rep_id
from customer
where not zip_code =‘22808’ and not sales_rep_id =’14’;
或: Select name, zip_code, sales_rep_id
from customer
where not (zip_code=‘22808’ or sales_rep_id =’14’)
/
![Page 70: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/70.jpg)
布尔运算的优先级优先级 运算符
1 ()2 NOT p
3 p AND q
4 p OR q
例:检索邮政编码为 22808 或 22809, 并且具有极好信誉等级的客户。
![Page 71: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/71.jpg)
Select name, zip_code , credit_rating
from customer
where (zip_code =‘22808’ or zip_code=‘22809’) and credit_rating=‘excellent’;
![Page 72: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/72.jpg)
2. 字符匹配—— LIKE 子句及通配符百分号(%)通配符:代表零个或多个字符的
字符串。例 1: 在 emp 表中查询姓名以字母 B 开头的所
有的雇员的姓名。 select name
from emp
where name like ‘B%’
/
![Page 73: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/73.jpg)
例 2 :列出地址中有 High 的客户的名称、地址。
select name , address
from customer
where address like ‘%High%’
/
![Page 74: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/74.jpg)
下划线( _ )通配符:代表任意一个字符。例:在 emp 表中查询姓名以 M 开始,且名字
正好为 5 个字母的所有雇员的姓名。 select name
from emp
where name like ‘M_ _ _ _’
/
注意:若要匹配通配符‘%’或‘ _’ 本身可使用换码字符“ \” 。
![Page 75: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/75.jpg)
Between运算符Select 列名From 表名Where 列名 between 低值 and 高值 ;
例 1 :列出客户 ID 在 303 及 306之间的客户的 ID 、名字及电话号码。
select id, name, phone
from customer
where id between ‘303’ and ‘306’;
![Page 76: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/76.jpg)
例 2 :列出客户的 ID 、姓名及电话号码,要求客户名字的开头是从 A 到 G之间的字母。
select id , name, phone
from customer
where name between ‘A’ and ‘H’;
![Page 77: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/77.jpg)
IN运算符Select 列名From 表名Where 列名 in ( 值 1 ,值 2 ,…值 n) ;
例 1 :查询客户 ID 为 303 、 305 、 403 及 406 的客户的 ID 、名字及电话号码。
select id, name, phone from customer where id in(‘303’,’305’,’403’,’406’);
![Page 78: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/78.jpg)
例 2 :查询具有 excellent 或 poor 信誉等级的客户名字及信誉等级的 SQL 语句。
select name, credit_rating
from customer
where credit_rating in(‘excellent’,’poor’)
/
![Page 79: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/79.jpg)
练习:使用 emp 、 customer 、 dept 、 region表
1. 显示在部门 31 及在部门 41工作的雇员的姓名、部门id 及工资。
2. 查询经理 ID 为 1 、 2 或 null 的所有雇员的姓名、职务及其经理 ID ,将结果按职务、姓名的字母顺序排序。
3. 显示不在部门 31 或 41工作,但工资高于 2000 元的所有雇员的姓名、部门 id 及工资。
4. 查询在部门 41工作,是 stock clerk 或 warehouse manager 的所有雇员的姓名、职位及部门 ID 。
5. 查询所有具有 poor 信誉等级的客户的姓名、客户所在区域名称及其销售代表的姓名和所在部门的名称。
![Page 80: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/80.jpg)
1. Select name, dept_id, salary from emp where dept_Id=’31’ or dept_id=’41’ ;
2. Select name, title, manager_id from emp where manager_id is null or manager_id=‘1’ or manager_id=‘2’ order by title, name;
3. Select name, dept_id, salary from emp where salary>2000 and not dept_id =’31’ And not dept_id =’41’;
![Page 81: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/81.jpg)
4. Select name,title, dept_id
from emp
where dept_id =’41’
and (title=‘stock clerk’ or title= ‘warehouse manager’);
5. Select C.name “customer”, R.name “region”, E.name “sales rep”, D.name “department”
from customer C, region R, emp Ee, dept D
where C.sales_rep_id=E.id
and C.region_id=R.id
and E.dept_id=D.id
and C.credit_rating=‘poor’;
![Page 82: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/82.jpg)
算术运算及内部函数 SQL 支持的算术运算符()、 × 、 / 、+、
-例 1 :写出一个 SQL查询,结果显示所有
warehouse manager 的工资每月增加 250 后的值。
Select name, salary+250
From emp
Where title=‘warehouse manager’;
![Page 83: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/83.jpg)
列名 描述 / 数据类型Product_id 产品惟一的标识号,最长为 7 个字符Warehouse_id 存储产品的仓库 id, 最长为 7 个字符Amount_in_stock 库存中每件产品的数量,最长为 9 个数字
Reorder_point 需要再订货的库存产品的最低数量,最长为 9 个数字
Max_in_stock 库存产品的最大值,最长为 9 个数字Out_of_stock_
explanation
产品无货的原因,最长为 255 个字符
Restock_date 产品再存货的日期,日期数据类型
Inventory 表:
![Page 84: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/84.jpg)
例 2: warehouse 101 的仓库经理想知道为每项产品订购 100 件后,是否会高于管理所规定的最大值。
select product_id,
max_in_stock - (amount_in_stock+100)
from inventory
where warehouse_id=‘101’
/
![Page 85: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/85.jpg)
例 3 : warehouse 201 的仓库经理决定对 20106 产品及 20108 产品各订购 100 件,产品到货后,如果所得到的每个产品新数量的一半被卖掉,还会剩多少件?该经理需要知道,这些存货量是否低于再订购点以及低多少 (即还需要订购产品的数量 ) 。
select product_id, (amount_in_stock+100)/2 , reorder point,
reorder_point-( (amount_in_stock+100)/2 )
from inventory
where warehouse_id=‘201’ and
(product_id=‘20106’ or product_id=‘20108’)
/
![Page 86: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/86.jpg)
内部函数数值函数函数名 返回值
ABS(m) m 的绝对值MOD(m,n) m 被 n除后的余数POWER(m,n) m 的 n 次方ROUND(m [,n] )
m 四舍五入至小数点后 n 位的值 (n缺省为 0)
TRUNC(m [,n]) m截断至 n 位小数位的值 (n 缺省为0)
![Page 87: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/87.jpg)
例 1 :对每项存货,显示存货量与再订购点之间的差值以及该差值的绝对值。
Select product_id,warehouse_id,
amount_in_stock-reorder_point, ABS(amount_in_stock-reorder_point)
From inventory
/
例 2 :显示每项存货被 9除后的余数。Select product_id,
warehouse_id,MOD(amount_in_stock,9)
From inventory;
![Page 88: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/88.jpg)
例 3 :显示每项存货量及存货量的平方。Select amount_in_stock,
POWER(amount_in_stock,2)
From inventory;
例 4 :1) 将每项存货量用 9除,将结果显示为最接近整数的四舍五入值。
select amount_in_stock/9,
ROUND(amount_in_stock/9)
from inventory;
![Page 89: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/89.jpg)
2) 将每项存货量用 9除,显示四舍五入到小数点后一位和后两位的结果。
select amount_in_stock/9, ROUND(amount_in_stock/9 , 1) , ROUND(amount_in_stock/9 , 2) from inventory;3 )将每项存货量用 9除,显示结果到最邻近
的十位及百位数。select amount_in_stock/9, ROUND(amount_in_stock/9 ,- 1) , ROUND(amount_in_stock/9 ,- 2) from inventory;
![Page 90: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/90.jpg)
例 5 :嵌套函数显示每次存货数被 81除后的余数四舍五入到最邻近的十位数的值。
Select ROUND(MOD(amount_in_stock,81),-1)
From inventory;
![Page 91: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/91.jpg)
重要的转换函数
NVL ( m,n ) : 如果 m 值为 null ,返回值为 n ,否则返回m 。To_char(…) :将数值转换成字符串。To_number(…) :将字符串转换成数值。
![Page 92: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/92.jpg)
例 1 :假设 emp 表,该表中 title 列可能存在 null 值,我们想在查询结果中中用‘ unknown’替代。
Select NVL(title,’unknown’)
From emp;
例 2 :我们想对以字符串存储的数进行计算。Select to_number(‘123.45’)+to_number(‘234.56’)
From dual;
例 3 :将 emp 表中雇员的工资用‘ $9,999,999.99’格式化。
Select id, to_char(salary, ‘$9,999,999.99’)
From emp;
![Page 93: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/93.jpg)
SUM(n) 和 AVG(n)函数SUM(n) 和 AVG(n)函数分别返回列中所有
值的和及平均值,他们都忽略空值,即并不把空值假定为 0 。
例 1 :显示 emp 表中,月工资的总和及平均值。
Select sum(salary) ,avg(salary)
From emp;
五、分组函数
![Page 94: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/94.jpg)
MAX(n) 和 MIN(n)函数MAX(n) 和 MIN(n)函数返回指定列中的最大值和最小值。这两个函数适用于所有数据类型。字符将按它的 ASCII 码计算,而且所有的大写字母比所有小写字母小。
例 2 :显示 warehouse manager 的最高工资和最低工资。
Select max(salary),min(salary)
From emp
Where title=‘warehouse manager’;
![Page 95: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/95.jpg)
Count()函数Count(*) :统计整个表的行数。Count(all n ) 和 count( n ) 函数 :显示指定列中已知值的个数。Count( distinct n )函数:返回指定列中不同值的个数。
例 3 :统计 emp 中不同的部门数及表的总行数。
Select count( distinct dept_id ), count(*)
From emp;
![Page 96: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/96.jpg)
列名 描述 / 数据类型
Ord_id 与项目相关的定单 ID ,最长为 3 个字符
Item_id 分配给每个项目的惟一的标识号,最长为 7个字符
Product_id 与该项目相关的产品 ID ,最长为 7 个字符
Price 该项目的价格,最长 11 位数,包括 2 位小数
Quantity 该项目的数量,最大为 9 位数
Quantity_shipped 已知产品的定单中该项目的发运数,最大为9 位数
Item 表:单一值和分组函数的结合
![Page 97: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/97.jpg)
例 1 :显示定单号 100 中所有订货的合计平均值
Select avg(price * quantity )From itemWhere ord_id =‘100’;例 2 :显示定单号 100 中所有订货价格合计的
最大值与最小值。Select max( price * quantity ), min(price* quantity)From itemWhere ord_id=‘100’;
![Page 98: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/98.jpg)
显示指定组的信息Select 列名
from 表名 where 条件 group by 列名 1[, 列名 2…]
having 条件 【 order by 条件】;Where 子句限制 select 语句显示的行
数, having 子句限制了显示的组数。Having 子句中可以使用任何分组函数。
![Page 99: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/99.jpg)
Group By 子句例 1 :显示 emp 表中每种工作职务人的平均工资值,职务按字母顺序排列。
Select title, count(*), avg(salary)From empGroup by titleOrder by title;
Count(*)函数返回每个类目内的行数。其中空值被考虑在内了。
![Page 100: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/100.jpg)
例 2 :显示每个部门员工的最高工资、最低工资,其中该部门中的人数要 1 个以上。按部门排序。
Select dept_id, max(salary), min(salary)
From emp
Group by dept_id
Having count(*)>1
Order by dept_id;
![Page 101: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/101.jpg)
练习:
1. 显示部门名称和 id 以及该部门的员工人数,要求部门的人数要大于 1 。按部门员工总数降序排列。
2. 显示地区 id和地区名以及该地区的客户数。
3.按部门分组,显示平均工资大于 1200元的经理姓名。
![Page 102: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/102.jpg)
1. Select emp.dept_id “id”,
dept.name “department”,
count(emp.id) “employees”
from emp, dept
where emp.dept_id=dept.id
group by emp.dept_id,dept.name
having count(emp.id)>1
order by count(emp.id) desc;
![Page 103: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/103.jpg)
2. Select region.id,region.name,count(customer.id)
from region,customer
where region.id=customer.region_id
group by region.id,region.name;
3.select E.manager_id,M.name,avg(M.salary)
from emp E, emp M
where E.manager_id=M.id
group by E.manager_id,M.name
having avg(M.salary)>1200;
![Page 104: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/104.jpg)
嵌套查询和集合查询嵌套查询或子查询:它允许我们根据另一个查询的结果检索数据。
select ……
from ……
where ……
(select……
from ……
where……)
外层查询,后执行这个查询
子查询,先执行这个内层查询
![Page 105: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/105.jpg)
单一行的子查询
例 1 :显示所有工资大于平均工资的雇员的姓名,工资。
Select name, salary
From emp
Where salary>(select avg(salary)
from emp);
![Page 106: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/106.jpg)
多行子查询:多行比较运算符
运算符 意义
IN 等于子查询返回值中的任一值,则为 true
NOT IN 不等于或不同于子查询返回值中的任一值,则为true
ANY 一个值与子查询返回值中的每一个值比较。只要有一个成立,则为 true 。
ALL 一个值与子查询返回值中的每一个值比较。都成立时,则为 true 。
![Page 107: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/107.jpg)
例 1 :在 dept 表中,显示至少有一位雇员的部门的名称。方法一: select d.name
from dept d, emp e
where d.id=e.dept_id
group by d.name
having count(e.id) >=1;
![Page 108: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/108.jpg)
方法二: select distinct name
from dept
where id in (select dept_id
from emp);
![Page 109: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/109.jpg)
列名 描述 / 数据类型
Id 每个定单的惟一标识号,最长为 3 个字符
Customer_id 客户的惟一标识号,最长为 3 个字符
Date_ordered 定单的订货日期,日期数据类型
Date_shipped 定单的发运日期,日期数据类型
Sales_rep_id 负责定单的销售代表的惟一标识号,最长为3 个字符
Total 定单的总金额,最长 11 位数,包括 2 位小数
Payment_type 支付方式,最长为 6 个字符
Order_filled 定单是否已经填写,最长为 1 个字符
Ord表
![Page 110: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/110.jpg)
例 2 :显示所有在 1992 年 8 月 31 日发出定单的顾客。
select name from customer where id in (select customer_id from ord where date_ordered=’31-8 月 -92’);
![Page 111: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/111.jpg)
例 3 :显示任职于一个现有部门的雇员的姓名。 select name
from emp
where dept_id = any(select id
from dept);
例 4 :找出工资最低的雇员。 select name
from emp
where salary<=all ( select salary
from emp);
![Page 112: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/112.jpg)
多列子查询Select …
from …
where ( 列名 1 ,…列名 n) in
(select 列名 1 ,…列名 n
from …
where…);
那层查询中的多列。跟外层查询的列数相同,并且有相同的对应域。
![Page 113: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/113.jpg)
例 1 :根据表 emp显示经理 id 为 10 且工资和职务相同的所有雇员的姓名、部门号、工资和开始工作的日期。
select name, dept_id, salary, start_date
from emp
where (salary, title) in
(select salary, title
from emp
where manager_id=‘10’);
![Page 114: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/114.jpg)
使用子查询创建表拷贝表的结构 例 1 :拷贝 emp 表的结构,而不要它的
数据。将新表称为 worker 。 create table worker
as select *
from emp
where 1<>1;
![Page 115: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/115.jpg)
拷贝表中的若干列及其数据例 2: 创建一个表,它包含有 VP职务的雇员的
姓名和部门号。新表名为 vice_president 。 create table vice_president as
select name, dept_id
from emp
where title like ‘%VP%’;
![Page 116: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/116.jpg)
利用子查询更新表
列名 描述 / 数据类型
Id 每个仓库的惟一标识号,最长为 7 个字符
Region_id 仓库所在的区域 id, 最长为 3 个字符
City 仓库所在的城市,最长为 20 个字符
Phone 仓库的电话号码最长为 20 个字符
Manager_id 仓库经理的 id, 最长为 3 个字符
Warehouse表
![Page 117: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/117.jpg)
例 1 :由于上一年出色的完成了任务,因此,对位于上海的仓库的经理的所有下属雇员每人工资长 1000 元。
update emp
set salary =salary+1000
where manager_id =(select manager_id
from warehouse
where city=‘上海’ ) ;
![Page 118: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/118.jpg)
例 2 :假设上海的仓库经理辞职了,由 John临时代替。更新 emp 表
update emp
set manager_id=(select id
from emp
where name=‘John’)
where manager_id=(select manager_id
from warehouse
where city=‘上海’ ) ;
![Page 119: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/119.jpg)
利用子查询向表内插入数据
例 1 :将所有在 10 号部门工作的雇员插入到前面建立的 worker 表中。
insert into worker
select *
from emp
where dept_id =‘10’;
![Page 120: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/120.jpg)
利用子查询从表中删除行
例 1 :假定由于业务不足,位于上海的仓库已经关闭。在 emp 表中删除所有在这个仓库工作的雇员。
delete from emp
where manager_id=(select manager_id
from warehouse
where city=‘上海’ ) ;
![Page 121: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/121.jpg)
集合运算符集合运算符 union( 并 ) 、 Intersect (交)和
minus(差 ) 允许将单独的 select 语句的结果组合起来。Union运算符
该运算符允许我们把多个 select 语句的查询结果合并起来。
例 1:显示所有 region_id 为 1 的顾客姓名和在该地区的部门名称。
![Page 122: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/122.jpg)
select name
from customer
where region_id=‘1’
union
select name
from dept
where region_id=‘1’;
![Page 123: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/123.jpg)
Intersect运算符该运算符允许找出两个表共有的行。
例 2 :显示所有被指派了客户的销售代表的id 。
select sales_rep_id
from customer
intersect
select id
from emp;
![Page 124: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/124.jpg)
Minus运算符该运算符允许我们确定存在于一个表中但不存在于另一个表中的行。
例 3 :由于内部培训,有些销售代表还没有被指派客户,显示这些销售代表的名字。
select name from emp where id = ( select id from emp minus select sales_rep_id from customer);
![Page 125: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/125.jpg)
练习:1. 显示定单总金额超过所有定单平均值的顾客的姓名和信誉等级。
2. 创建一个表,它包括信誉等级为 poor 的所有客户信息。表名为 low_rating.
![Page 126: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/126.jpg)
1 、 select customer.name,
customer.credit_rating
from customer,ord
where ord.total>(select avg(total)
from ord)
and ord.customer_id=customer.id;
2. Create table low_rating
as select *
from customer
where credit_rating=‘poor’; 返回
![Page 127: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/127.jpg)
PL/SQL 的块结构 declare 变量、常量、游标、嵌套的 pl/sql 过程以及函数的定义 begin 执行部分 exception 错误或异常处理 end;注:只有 begin 部分是必须的, declare 和 exception 部分为可选的。
ORACLE 的 PL/SQL
![Page 128: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/128.jpg)
变量 变量命名规则: 1. 以字母 A—Z 开头。 2. 后可跟字母,数字( 0—9 )或 $,#,_ 。 3. 长度不超过 30 。 4. 变量名不能有空格。5. 可用数据类型 varchar2 、 char 、 number 、 binary_integer
( 带 符 号 的 整 型 变量 ) 、 pls_integer 、 date 、 boolen
![Page 129: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/129.jpg)
范例 1 :匿名块 declare hundreds_counter number(1,-2); begin hundreds_counter :=100; loop dbms_output.put_line(hundreds_counter); hundreds_counter:=hundreds_counter+100; end loop; exception when others then dbms_output.put_line(‘that is an high as we can
go.’); end;
![Page 130: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/130.jpg)
函数和过程块 function 函数名 [ (参数列表) ]
return 数据类型 is 或 as
变量声明 begin
执行部分 [exception
错误或异常处理 ]
end;
![Page 131: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/131.jpg)
范例 3: 过程块 procedure 过程名 [ (参数列表) ] is 或
as
变量声明 begin
执行部分 [exception
错误或异常处理 ]
end;
![Page 132: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/132.jpg)
流程控制分支结构:
IF 语句 :
if 条件 then…
else…
end if;
IF…ELSIF 语句 : if 条件 then… elsif 条件 then… elsif 条件 then… else… end if;
![Page 133: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/133.jpg)
例 : 使用 if…elsif 语句确定等级 declare
v_score number := 85;
v_lettergrade char(1);
begin
if v_score>=90 then
v_lettergrade :=‘A’;
elsif v_score>=80 then
v_lettergrade :=‘B’;
elsif v_score>=70 then
v_lettergrade :=‘C’;
elsif v_score>=60 then v_lettergrade :=‘D’; else v_lettergrade :=‘E’; end if; dbms_output.put_line( ‘your letter grade is:’ || v_lettergrade)
![Page 134: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/134.jpg)
循环结构 for循环: for 循环变量 in [reverse] 低值 ..高值 loop …… end loop;例: begin for v_loopcounter in 1..5 loop dbms_output.put_line(‘loop counter is’ ||
v_loopcounter); end loop; end;
![Page 135: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/135.jpg)
While 循环 while 条件 loop …… end loop; 例: declare v_calc number :=0; begin while v_calc <=10 loop v_calc :=v_calc +1; dbms_output.put_line(‘the value of v_calc
is’ || v_calc); end;
![Page 136: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/136.jpg)
Exit 和 exit when 语句范例:在 while循环中使用 exit when 语句 declare
v_radius number :=2;
begin
while true loop
dbms_output.put_line(‘the area is’ || mypi * v_radius * v_radius);
exit when v_radius = 10;
v_radius=v_radius+2;
end;
![Page 137: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/137.jpg)
Loop循环 loop
……
exit when…
end loop;
![Page 138: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/138.jpg)
declare v_radius number :=2; begin loop dbms_output.put_line(‘the area is’ ||
mypi * v_radius * v_radius); v_radius=v_radius+2; exit when v_radius >10; end loop; end;
![Page 139: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/139.jpg)
伪列Currval 和 nextval 与序列 sequence 一起使用。序列用来产生惟一的数字。 Currval返回序列的当前值,而 nextval 在序列中增加新值并返回此值。
如: emp_sequence 序列用来为 emp 表的主关键字生成惟一值 :
Create sequence student_sequence
start with 10000
increment by 1;
![Page 140: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/140.jpg)
Insert into emp(id,name,title,salary)
Values(emp_sequence.nextval,'Sam', 'President', 4500);
Insert into emp(id,name,title,salary)
Values(emp_sequence.nextval,'Thomas', 'Sales Representative', 1500);
可用下面的 SQL 语句返回序列的当前值。Select emp_sequence.currval
From dual;
![Page 141: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/141.jpg)
% type
pl/sql 变量可用于处理存储在数据库中的数据,在这种情况下,变量应该拥有与表列相同的类型。
如: declare
v_empid emp.id%type;
![Page 142: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/142.jpg)
% rowtype
Declare
v_deptrecord dept%rowtype;
定义了一个记录,该记录中的字段将与 rooms表中的列相对应。 v_deptrecord 可拥有下面的结构。
( id varchar2(3),
name varchar2(20),
region_Id varchar2(3))
![Page 143: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/143.jpg)
游标PL/SQL 有两种类型的游标: 1. 显式游标。——返回多行的查询 2. 隐式游标。——返回单行的查询处理显式游标的步骤: 1. 声明游标 2. 为查询打开游标 3. 取得结果放入 pl/sql 变量中。 4. 关闭游标
![Page 144: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/144.jpg)
1.声明游标
DECLARE v_empid emp.id%TYPE; v_name emp.name%TYPE; v_title emp.title%TYPE := ' Sales
Representative ';
CURSOR c_emp IS SELECT id, name FROM emp WHERE title = v_title;
![Page 145: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/145.jpg)
2. 为查询打开游标BEGIN OPEN c_emp; 3.取得结果放入 pl/sql 变量中LOOP FETCH c_emp INTO v_empid, v_name; EXIT WHEN c_emp%NOTFOUND; END LOOP; 4. 关闭游标 close c_emp;End;
![Page 146: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/146.jpg)
也可以使用参数化游标: declare cursor c_emp(p_title emp.title%TYPE ) is
SELECT id, name FROM emp WHERE title = p_title; v_empid emp.id%TYPE; v_name emp.name%TYPE; begin open c_emp(' Sales Representative ‘); ……
![Page 147: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/147.jpg)
游标属性% notfound:游标 fetch 语句没有返回行,则该属性计算为 true
%found:游标 fetch 语句返回行,则该属性计算为 true
%rowcount: 该属性返回游标打开后至现在,由 fetch 语句已获取的行数。% isopen :游标是打开的,该属性为 true.
![Page 148: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/148.jpg)
处理隐式游标BEGIN
UPDATE emp
SET salary = 1000
WHERE id = ‘9’;
IF SQL%NOTFOUND THEN
INSERT INTO emp (id, salary)
VALUES (‘9’, 1000);
END IF;
END;
![Page 149: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/149.jpg)
使用 SQL%rowcount 可达到同样的目的BEGIN
UPDATE emp
SET salary = 1000
WHERE id = ‘9’;
IF SQL%rowcount=0 THEN
INSERT INTO emp (id, salary)
VALUES (‘9’, 1000);
END IF;
END;
![Page 150: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/150.jpg)
游标循环DECLARE
v_empid emp.id%TYPE;
v_name emp.name%TYPE;
CURSOR c_salesrep IS
SELECT id, name
FROM emp
WHERE title = ' Sales Representative ';
![Page 151: 第四章 SQL 和 PL/SQL](https://reader033.fdocuments.net/reader033/viewer/2022061418/56813739550346895d9ec9e6/html5/thumbnails/151.jpg)
BEGIN
OPEN c_salesrep;
LOOP
FETCH c_salesrep INTO v_empid, v_name;
EXIT WHEN c_salesrep%NOTFOUND;
insert into sales_rep (id,name,department )
values (v_empid, v_name, ‘sales');
END LOOP;
CLOSE c_salesrep;
END; 返回