• 使用UPDATE语句修改表中的现有值:
• 如果需要,可以一次更新多行。
UPDATE table
SET column= value[, column = value, ...]
[WHERE condition];
可以使用UPDATE语句修改表中的现有值。
在该语法中:
table 是表名称
column 是表中要填充的列的名称
value 是该列相应的值或子查询
condition 标识要更新的行,由
列名、表达式、常数、子查询和比较运算符组成
通过查询表来显示更新的行就可以确认更新操作。
注:通常情况下,请使用WHERE子句中的主键列来指定要更新的一行。使用其它列时可
能会意外地更新其它的行。例如,用姓名标识EMPLOYEES表中的一行是危险的,因为可
能有多名雇员具有相同的姓名。
• 如果指定WHERE子句,则可以修改特定一行或多行
的值:
UPDATE employees
SET department_id = 50
WHERE employee_id = 113;
•
如果省略WHERE子句,则可以修改表中所有行的值:
UPDATE copy_emp
SET department_id = 110;
• 指定SET column_name= NULL可将列值更新为
NULL。
如果指定WHERE子句,则UPDATE语句可以修改特定一行或多行的值。示例显示
如何将雇员113 (Popp) 调到部门50。
如果省略WHERE子句,则会修改该表中所有行的值。检查COPY_EMP表中的更新行。
SELECT last_name, department_id FROM copy_emp;
例如,曾经担任SA_REP职务的某个雇员现在的职务为IT_PROG。因此,需更新其
JOB_ID并将其佣金字段设置为NULL。
UPDATE employees
SET job_id = 'IT_PROG', commission_pct = NULL
WHERE employee_id = 114;
注:COPY_EMP表与EMPLOYEES表具有相同的数据。
更新雇员113 的职务和薪金,使其与雇员205 的职务和
薪金一样。
UPDATE employees
SET job_id = (SELECT job_id FROM employees WHERE employee_id = 205),
salary = (SELECT salary FROM employees WHERE employee_id = 205)
WHERE employee_id = 113;
通过编写多个子查询,可以在UPDATE语句的SET子句中更新多个列。语法如下:
UPDATE table
SET column =
(SELECT column
FROM table
WHERE condition)
[ ,
column =
(SELECT column
FROM table
WHERE condition)]
[WHERE condition ];
示例还可以编写如下:
UPDATE employees
SET (job_id, salary) = (SELECT job_id, salary FROM employees WHERE employee_id = 205)
WHERE employee_id = 113;
在UPDATE语句中使用子查询可根据另一个表中的值来更新
某一个表中的行值:
UPDATE copy_emp
SET department_id = (SELECT department_id
FROM employees
WHERE employee_id = 100)
WHERE job_id = (SELECT job_id
FROM employees
WHERE employee_id = 200);
可以在UPDATE语句中使用子查询来更新表中的值。示例根据EMPLOYEES表中的
值更新COPY_EMP表。它将与雇员200 具有相同职务ID 的所有雇员的部门编号都更改为
雇员100 的当前部门编号。
使用DELETE语句可以从表中删除现有行:
DELETE [FROM] table
[WHERE condition];
DELETE语句语法
使用DELETE语句可以从表中删除现有行。
在该语法中:
table 是表名称
condition 标识要删除的行,由
列名、表达式、常数、子查询和比较运算符组成
注:如果没有删除任何行,则会在SQL Developer 的“Script Output(脚本输出)”选项
卡上返回消息“0 rows deleted”。
• 如果指定WHERE子句,则会删除特定行:
DELETE FROM departments WHERE department_name = 'Finance';
• 如果省略WHERE子句,则会删除表中的所有行:
DELETE FROM copy_emp;
通过在DELETE语句中指定WHERE子句,可以删除特定行。第一个示例从
DEPARTMENTS表中删除了Accounting 部门。通过使用SELECT语句显示被删除的行,
可以确认删除操作。
SELECT * FROM departments WHERE department_name = 'Finance';
但是,如果省略WHERE子句,则会删除该表中的所有行。第二个示例从
COPY_EMP表中删除了所有行,因为没有指定WHERE子句。
示例:
删除WHERE子句中标识的行。
DELETE FROM employees WHERE employee_id = 114;
DELETE FROM departments WHERE department_id IN (30, 40);
在DELETE语句中使用子查询可根据另一个表中的值来删除
某一个表中的行:
DELETE FROM employees
WHERE department_id =
(SELECT department_id FROM departments WHERE department_name LIKE '%Public%');
使用子查询可根据另一个表中的值来删除某一个表中的行。示例中删除了部门名称
包含字符串“Public”的部门的所有雇员。
子查询将根据包含字符串“Public”的部门名称来搜索DEPARTMENTS表以找到部门编
号。然后,子查询将该部门编号反馈给主查询,主查询将根据该部门编号从EMPLOYEES
表中删除有关数据行。
• 从表中删除所有行,
使表为空并保留表结构不变
• 是
数据定义语言(DDL) 语句而不是DML 语句,无法
轻易将其取消
• 语法:
TRUNCATE TABLE table_name;
• 示例:
TRUNCATE TABLE copy_emp;
清空表的一个更有效的方法就是使用TRUNCATE语句。
可以使用TRUNCATE语句从表或集群中快速删除所有行。使用TRUNCATE语句删除行比
使用DELETE语句要快,原因如下:
• TRUNCATE语句是数据定义语言(DDL) 语句,它不会生成回退信息。
• 截断一个表不会触发该表的删除触发器。
如果表是具有引用完整性约束条件的父表,则不能截断表。需要在发出TRUNCATE语句
之前禁用该约束条件。
数据库事务处理由以下语句之一组成:
• 用于对数据进行一次一致更改的DML 语句
• 一条DDL 语句
• 一条数据控制语言(DCL) 语句
Oracle Server 在事务处理的基础上确保数据的一致性。事务处理令你在更改数据时具有更
高的灵活性和控制力,还可以确保在用户进程失败或系统出现故障时保持数据的一致性。
事务处理由一些DML 语句组成,这些DML 语句用于对数据进行一次一致更改。例如,
在两个帐户之间转移资金时应涉及两个帐户,一个是借方帐户,另一个是贷方帐户,这
两个帐户的金额相同。这两个操作必须都失败或都成功,没有借方也就没有贷方。
事务处理类型
• 在执行第一条DML SQL 语句时开始。
• 在发生下列事件之一时结束:
– 发出COMMIT或ROLLBACK语句。
– 执行DDL 或DCL 语句(自动提交)。
– 用户退出SQL Developer 或SQL*Plus。
– 系统崩溃。
数据库事务处理何时开始和结束?
事务处理在遇到第一条DML 语句时开始,在发生以下事件之一时结束:
• 发出COMMIT或ROLLBACK语句。
• 发出DDL 语句,例如CREATE。
• 发出DCL 语句。
• 用户退出SQL Developer 或SQL*Plus。
• 计算机出现故障或系统崩溃。
一个事务处理结束后,下一个可执行的SQL 语句会自动启动下一个事务处理。
DDL 语句或DCL 语句是自动提交的,因此会隐式结束一个事务处理。
使用COMMIT和ROLLBACK语句,可以:
• 确保数据的一致性
• 在使更改变成永久性更改之前预览数据更改
• 按逻辑关系对相关操作进行分组
使用COMMIT和ROLLBACK语句,可以控制将数据更改变成永久性更改。
使用COMMIT、SAVEPOINT和ROLLBACK语句可以控制事务处理的逻辑。
注:不能对SAVEPOINT使用COMMIT语句。SAVEPOINT不是符合ANSI 标准的SQL。
• 使用SAVEPOINT语句可在当前事务处理中创建一个
标记。
• 使用ROLLBACK TO SAVEPOINT语句可回退到该标记。
UPDATE...
SAVEPOINT update_done;
INSERT...
ROLLBACK TO update_done;
使用SAVEPOINT语句可以在当前事务处理中创建一个标记,该标记会将事务处理分成
更小的部分。然后,使用ROLLBACK TO SAVEPOINT语句可以放弃该标记之后的待定
更改。
请注意,如果创建的第二个保存点的名称与较早保存点的名称相同,则会删除较早保存点。
• 在下列情况下会发生自动提交:
– 发出DDL 语句
– 发出DCL 语句
– 从SQL Developer 或SQL*Plus 正常退出,而没有显式
发出COMMIT或ROLLBACK语句
• 当异常终止SQL Developer 或SQL*Plus 或者系统出现
故障时会发生自动回退。
注:在SQL*Plus 中,AUTOCOMMIT命令可以在ON 或OFF 之间切换。如果设置为ON,
则在执行单个DML 语句后立即提交该语句。你不能回退更改。如果设置为OFF,则仍
可以显式发出COMMIT语句。此外,也可以在发出DDL 语句或退出SQL*Plus 时发出
COMMIT语句。在SQL Developer 中会跳过SET AUTOCOMMIT ON/OFF命令。只有启用
“Autocommit(自动提交)”首选项,才会在从SQL Developer 正常退出时提交DML 语
句。要启用“Autocommit(自动提交)”,请执行以下步骤:
• 在“Tools(工具)”菜单中,选择“Preferences(首选项)”。在“Preferences
(首选项)”对话框中,展开“Database(数据库)”并选择“Worksheet Parameters
(工作表参数)”。
• 在右侧窗格中,选择“Autocommit in SQL Worksheet(以SQL 工作表的形式自动提
交)”选项。单击“OK(确定)”。
系统故障
当系统出现故障而中断事务处理时,就会自动回退整个事务处理。这样可以防止因为错误
而导致数据发生不必要的更改,还可以使表返回到上一次提交时的状态。Oracle Server 通
过这种方式保护表的完整性。
在SQL Developer 中,通过在“File(文件)”菜单中选择“Exit(退出)”,可以正常退
出会话。在SQL*Plus 中,在提示符下键入EXIT命令可以正常退出。关闭窗口则被解释
为异常退出。
- 执行COMMIT或ROLLBACK操作之前的数据状态
• 可以将数据还原到以前的状态。
• 当前用户可以使用SELECT语句查看DML 操作的结果。
• 其他用户不能查看当前用户发出的DML 语句的结果。
• 受影响行已锁定,其他用户不能更改受影响行中的数据。
在提交事务处理之前,其间进行的所有数据更改都是临时的。
发出COMMIT或ROLLBACK语句之前数据的状态如下所述:
• 数据处理操作主要影响
数据库缓冲区,因此可以将数据还原到以前的状态。
• 当前用户可以通过对表进行查询来查看数据处理操作的结果。
• 其他用户不能查看当前用户执行的数据处理操作的结果。Oracle Server 会建立读
一致性,从而确保每个用户看到的数据都是上次提交时的数据。
• 受影响行已锁定,其他用户不能更改受影响行中的数据。
• 数据更改已保存在数据库中。
• 已改写以前的数据状态。
• 所有用户都可以查看结果。
• 受影响行上的锁已被释放,其他用户可以对这些行进行
处理。
• 所有保存点都已被清除。
使用COMMIT语句可以使所有待定更改变成永久性更改。执行COMMIT语句之后会发生
以下情况:
• 数据更改已写入数据库中。
• 以前的数据状态不再适用于正常的SQL 查询。
• 所有用户都可以查看事务处理的结果。
• 受影响行上的锁已被释放,其他用户可以对这些行执行新的数据更改。
• 所有保存点都已被清除。
• 进行更改:
DELETE FROM employees WHERE employee_id = 99999;
INSERT INTO departments VALUES (290, 'Corporate Tax', NULL, 1700);
• 提交更改:
COMMIT;
在示例中,从EMPLOYEES表中删除了一行并向DEPARTMENTS表中添加了新行。
通过发出COMMIT语句已保存所做的更改。
示例:
删除DEPARTMENTS表中的部门290 和300 并更新EMPLOYEES表中的一行。保存数据
更改。
DELETE FROM departments WHERE department_id IN (290, 300);
UPDATE employees SET department_id = 80 WHERE employee_id = 206;
COMMIT;
使用ROLLBACK语句放弃所有待定更改之后会有如下结果:
• 数据更改已取消。
• 数据已还原到以前的状态。
• 受影响行上的锁已被释放。
DELETE FROM copy_emp;
ROLLBACK;
DELETE FROM test;
25,000 rows deleted.
ROLLBACK;
Rollback complete.
DELETE FROM test WHERE id = 100;
1 row deleted.
SELECT * FROM test WHERE id = 100;
No rows selected.
COMMIT;
Commit complete.
在试图从TEST表中删除一条记录时,可能会意外地清空该表。但是,可以更正该错误,
然后重新发出适当的语句,使数据更改变成永久性更改。
• 如果在执行期间单个DML 语句失败,则只会回退该
语句。
• Oracle Server 会实施一个隐式保存点。
• 保留其它所有更改。
• 用户应通过执行COMMIT或ROLLBACK语句显式终止
事务处理。
如果检测到语句执行错误,则可以通过隐式回退来放弃事务处理的一部分。如果执行事务
处理期间单个DML 语句失败,则可使用语句级回退来取消其影响,但不放弃事务处理中
前面的DML 语句所做的更改。用户可以显式地提交或回退这些DML 语句。
Oracle Server 会在任意DDL 语句之前和之后发出隐式提交。因此,即使DDL 语句未成功
执行,你也不能回退前面的语句,因为服务器已发出提交。
通过执行COMMIT或ROLLBACK语句可以显式终止事务处理。
• 读一致性可以确保用户所看到的数据始终是一致的。
• 一个用户进行的更改不会与另一个用户进行的更改相
冲突。
• 读一致性可以确保对于同一数据:
– 读取者不必等待写入者完成操作即可读取
– 写入者不必等待读取者完成操作即可写入
– 写入者必须等待其他写入者完成操作才可写入
数据库用户可通过以下两种方式访问数据库:
• 读取操作(SELECT语句)。
• 写入操作(INSERT、UPDATE、DELETE语句)。
你需要使用读一致性来确保达到如下效果:
• 保证数据库读取者和写入者看到的数据是一致的。
• 读取者看不到正在更改的数据。
• 保证写入者对数据库的更改是在一致方式下完成的。
• 一个写入者进行的更改不会中断另一个写入者正在进行的更改,也不会与之相冲突。
建立读一致性的目的是为了确保每个用户看到的都是在DML 操作开始之前上次提交的
数据。
注:同一用户可以登录不同的会话。每个会话均以上述方式维护读一致性,即使这些会话
是同一用户的会话也如此。
读一致性是自动实现的。它在还原段中保留一个部分数据库的副本。读一致性映像由表中
的已提交数据和还原段中正在更改且尚未提交的旧数据组成。
在对数据库执行插入、更新或删除操作时,Oracle Server 会在数据发生更改之前创建它的
副本,并将其写入到还原段中。
除进行更改的人员之外,所有读取者看到的仍是更改开始之前的数据库,他们看到的是
还原段的数据“快照”。
在将更改提交到数据库之前,只有正在修改数据的用户可以看到数据库中的更改内容。
其他所有人看到的都是还原段中的快照。这样可以保证数据读取者能读取到一致的数据,
而不是当前正在进行更改的数据。
提交DML 语句之后,任何发出SELECT语句的用户都可以看到对数据库所做的更改。
还原段文件中旧数据占用的空间已被释放出来,可供重新使用。
如果回退事务处理,则会取消这些更改:
• 还原段中原始的旧版本数据已写回到表中。
• 所有用户看到的都是事务处理开始之前的数据库。
• 锁定EMPLOYEES表中job_id为SA_REP的行。
SELECT employee_id, salary, commission_pct, job_id FROM employees WHERE job_id = 'SA_REP'
FOR UPDATE
ORDER BY employee_id;
• 仅当发出ROLLBACK或COMMIT语句时才释放锁。
• 如果SELECT语句要锁定另一个用户已锁定的某一行,
数据库就会一直等待到该行可用为止,然后返回
SELECT语句的结果。
SELECT语句中的FOR UPDATE子句
当你针对数据库发出SELECT语句来查询某些记录时并不会锁定所选行。通常情况下这
样做是有必要的,因为默认情况下任何指定时间锁定的记录数量保持在绝对最低水平:
也就是只锁定那些已更改但尚未提交的记录。只有那样,其他用户才能够读取更改前的
记录(数据的“前像”)。但是,有时需要在程序中对某组记录进行更改之前将其锁定。
使用Oracle 提供的SELECT语句的FOR UPDATE子句即可执行该锁定。
发出SELECT...FOR UPDATE语句时,关系数据库管理系统(RDBMS) 会自动获得对
由SELECT语句标识的
所有行的行级互斥锁
,因此可暂挂这些记录“仅供你进行更改”。
其他人将无法更改这些记录,直至你执行ROLLBACK或COMMIT语句为止。
你可以将可选的关键字NOWAIT附加到FOR UPDATE子句中,告知Oracle Server 在另一
用户锁定该表时不要等待。在这种情况下,可以立即将控制权返回给你的程序或SQL
Developer 环境,以便你可以执行其它工作或者仅仅等待一段时间后重试。如果没有
NOWAIT子句,则会暂时终止你的进程,直至其他用户通过发出COMMIT或ROLLBACK
命名释放锁而使该表可用为止。
• 可以针对多个表在SELECT语句中使用FOR UPDATE
子句。
SELECT e.employee_id, e.salary, e.commission_pct FROM employees e JOIN departments d USING (department_id) WHERE job_id = 'ST_CLERK' AND location_id = 1500
FOR UPDATE
ORDER BY e.employee_id;
• 已锁定EMPLOYEES和DEPARTMENTS表中的所有行。
• 使用FOR UPDATE OF column_name来限定要更改
的列,此时只会锁定特定表中的行。
在示例中,该语句锁定了EMPLOYEES表中JOB_ID设置为ST_CLERK且
LOCATION_ID设置为1500 的那些行,同时还锁定了DEPARTMENTS表中
LOCATION_ID的部门设置为1500 的那些行。
你可使用FOR UPDATE OF column_name来限定要更改的列。FOR UPDATE子句中的OF
列表并没有限制你只更改选定行的那些列。所有行仍处于锁定状态;如果仅仅在查询中列
出了FOR UPDATE子句而在OF关键字后没有添加任何列,那么,数据库将会锁定FROM
子句列出的所有表中的所有指定行。
以下语句只锁定了EMPLOYEES表中ST_CLERK位于LOCATION_ID1500 的那些行,而
没有锁定DEPARTMENTS表中的任何行:
SELECT e.employee_id, e.salary, e.commission_pct FROM employees e JOIN departments d USING (department_id) WHERE job_id = 'ST_CLERK' AND location_id = 1500
FOR UPDATE OF e.salary
ORDER BY e.employee_id;
在以下示例中,数据库得知要等待五秒钟该行才可用,因而此时会将控制权返回给用户。
SELECT employee_id, salary, commission_pct, job_id FROM employees WHERE job_id = 'SA_REP'
FOR UPDATE WAIT 5
ORDER BY employee_id;