1、数据库操作语句(重点)DML(Data Manipulation Language)数据操纵语言命令使用户能够查询数据库以及操作已有数据库中的数据。包括之前学习的 SELECT 语句,还有以下表中的语句:语 句 描 述 INSERT 插 入 新 行 UPDA 修 改 (更 新 )已 经 存 在 的 行 ELTE 删 除 表 中 已 经 存 在 的 行 插入数据可以使用 INSERT 命令,向已经存在的表插入数据,语法格式如下:INSERT INTO 表名 (字段列表) VALUES(表达式1, 表达式2,.)|QUERY语句;1数据插入基本语法最常见的插入操作可使用以下的语法(该形式一次只能插
2、入一行数据) :INSERT INTO 表名(字段列表) VALUES ( 表达式列表); 插入字段的值的类型要和字段的类型一一对应。字符串类型的字段值必须用单引号括起来,例如:CLERK 。字符串类型的字段值超过定义的长度会出错, 最好在插入前进行长度校验。字段列表如果省略则代表全部字段。范例:表的部分字段插入练习。将新雇员插入到 emp 表:INSERT INTO emp(empno,ename,job)VALUES (1000, 小李, CLERK);这样只插入了一条记录,其他没有插入的字段,系统会填写为表的默认值。如果在表的创建时没有说明默认值,则将插入 NULL 值。日期类型的字段值
3、也要用单引号括起来,如10-1 月-03。日期型的数据默认格式为 DD-MON-YY,默认的世纪为当前的世纪,默认的时间为午夜 12 点。如果指定的世纪不是本世纪或时间不是午夜 12 点,则必须使用 TO_DATE 系统函数对字符串进行转换。范例:时间字段的插入练习。将新雇员插入到 emp 表:INSERT INTO emp(empno,ename,job,hiredate)VALUES (1001, 小马, CLERK, 10-1月-03);插入的雇员雇佣时间为 2003 年 1 月 10 日。注意:时间的默认格式为 DD-MON-YY。范例:表的全部字段的插入练习。INSERT INTO
4、dept VALUES (50, 培训部,深圳);说明:此种方式省略了字段名列表,要注意插入数据的顺序必须与表的字段默认顺序保持一致。如果不知道表的字段默认顺序,可以用 DESCRIBE 命令查看。范例:插入空值练习。INSERT INTO emp(empno,ename,job,sal) VALUES(1005,杨华, CLERK,null);说明:以上训练虽然指定了插入字段 sal,但在插入的数值位置指定了 NULL 值,所以 sal的插入值还是 NULL。练习:向雇员表插入全部字段的一条记录。2复制数据另一种插入数据(相当于复制 )方法的语法格式是:INSERT INTO 表名(字段列表
5、) SELECT(字段名1, 字段名2, .) FROM 另外的表名;该形式一次可以插入多行数据。范例:通过其他表插入数据的练习。 创建一个新表 managerCREATE TABLE manager AS SELECT empno,ename,sal FROM emp WHERE job=MANAGER; 从 emp 表拷贝数据到 managerINSERT INTO managerSELECT empno, ename, salFROM empWHERE job = CLERK;CREATE 命令用来根据已经存在的表创建新表。步骤 1 根据 emp 表创建一个新表manager,该表只有
6、3 个字段 empno,ename 和 sal,创建的同时将 emp 表中职务为 manager的雇员复制到其中。步骤 2 从 emp 表中把职务为 clerk 的雇员插入到 manager 表中。3使用序列使用 INSERT 语句时,可以通过序列来填写某些数值型或字符型的列。序列是一个要预先定义的有序的数值序列, 应该先建立一个序列,然后在插入语句中使用,序列将在以后章节中介绍。范例:插入数据中使用序列的练习。步骤 1:创建从 2000 起始,增量为 1 的序列 abc:CREATE SEQUENCE abc INCREMENT BY 1 START WITH 2000 MAXVALUE 9
7、9999 CYCLE NOCACHE;步骤 2:在 INSERT 语句使用序列,序列的名称为 abc:INSERT INTO manager VALUES(abc.nextval,小王,2500);INSERT INTO manager VALUES(abc.nextval,小赵,2800);步骤 3:使用 SELECT 语句观察结果:SELECT empno,ename,sal FROM emp;说明:步骤 1 创建序列,步骤 2 在插入时使用序列来填充雇员编号,使用 abc.nextval 可获得序列中的下一个值。后边两个记录的雇员编号来自序列,并且是递增的。 修改数据修改数据的语句 UP
8、DATE 对表中指定字段的数据进行修改,一般需要通过添加WHERE 条件来限定要进行修改的行,如果不添加 WHERE 条件,将对所有的行进行修改。(1) 修改数据的语句 UPDATE 的基本语法如下:UPDATE 表名 SET 字段名1=表达式1, 字段名2=表达式2, . WHERE 条件;范例:修改小李(编号为 1000)的工资为 3000,姓名改为李四。UPDATE empSET sal = 3000,ename=李四 WHERE empno = 1000;范例:将小李(编号为 1000)的雇佣日期改成当前系统日期,部门编号改为 50。UPDATE empSET hiredate=sys
9、date, deptno=50WHERE empno = 1000;如果修改的值没有赋值或定义,将把原来字段的内容清为 NULL。若修改值的长度超过定义的长度,则会出错。注意:本例中不能省略 WHERE 条件,否则将会修改表的所有行。 练习:将 SCOTT 的职务改为 MANAGER,工资改为 4000。范例:为所有雇员增加 100 元工资。注意:这里没有 WHERE 条件UPDATE empSET sal =sal+100;说明:若没有 WHERE 条件,将修改表的所有行。sal=sal+100 的含义是:对于每条记录,取出原来 sal 字段的工资,加 100 后再赋给 sal 字段。练习:
10、将 emp 表的部门 10 的雇员工资增加 10%。(2) UPDATE 语句的另外一种用法:UPDATE 表名 SET(字段名1, 字段名2, .)=(SELECT (字段名1, 字段名2, .) FROM 另外的表名) WHERE条件;范例:根据其他表修改数据。将 manager 表中编号为 1000 的记录的雇员名字和工资修改成为 emp 表的编号为 7788 的雇员的名字和工资。 首先写出编号为 7788 的雇员的名字和工资SELECT ename,sal FROM emp WHERE empno = 7788 然后根据此查询的结果修改 manager 表中编号为 1000 的雇员姓名
11、和工资UPDATE managerSET (ename, sal) =(SELECT ename,sal FROM emp WHERE empno = 7788)WHERE empno = 1000; 删除数据删除数据的基本语法如下:DELETE FROM 表名 WHERE 条件;要从表中删除满足条件的记录,WHERE 条件一般不能省略,如果省略就会删除表的全部数据。范例:删除雇员编号为 1000 的新插入的雇员。步骤 1:删除编号为 1000 的雇员:DELETE FROM emp WHERE empno=1000;步骤 2:显示删除结果:SELECT * FROM emp WHERE em
12、pno=1000;注意:DELETE 命令在 WHERE 中指定删除的记录。删除记录并不能释放 Oracle 中被占用的数据块表空间,它只是把那些被删除的数据块标成 unused。如果确实要删除一个大表里的全部记录,可以用 TRUNCATE 命令,它可以释放占用的数据块表空间,语法为:TRUNCATE TABLE 表名;说明:此命令和不带 WHERE 条件的 DELETE 语句功能类似,不同的是,DELETE 命令进行的删除可以撤销,但此命令进行的删除不可撤销。注意:TRUNCATE TABLE 命令用来删除表的全部数据而不是删除表,表依旧存在。数据库事务(重点)数据库事务的概念事务是由相关操
13、作构成的一个完整的操作单元。两次连续成功的 COMMIT 或ROLLBACK 之间的操作,称为一个事务。在一个事务内,数据的修改一起提交或撤销,如果发生故障或系统错误,整个事务也会自动撤销。比如,我们去银行转账,操作可以分为下面两个环节:(1) 从第一个账户划出款项。(2) 将款项存入第二个账户。在这个过程中,两个环节是关联的。第一个账户划出款项必须保证正确的存入第二个账户,如果第二个环节没有完成,整个的过程都应该取消,否则就会发生丢失款项的问题。整个交易过程,可以看作是一个事物,成功则全部成功,失败则需要全部撤消,这样可以避免当操作的中间环节出现问题时,产生数据不一致的问题。数据库事务是一个
14、逻辑上的划分,有的时候并不是很明显,它可以是一个操作步骤,也可以是多个操作步骤。我们可以这样理解数据库事务:对数据库所做的一系列修改,在修改过程中,暂时不写入数据库,而是缓存起来,用户在自己的终端可以预览变化,直到全部修改完成,并经过检查确认无误后,一次性提交并写入数据库,在提交之前,必要的话所做的修改都可以取消。提交之后,就不能撤销,提交成功后其他用户才可以通过查询浏览数据的变化。以事务的方式对数据库进行访问,有如下的优点:* 把逻辑相关的操作分成了一个组。* 在数据永久改变前,可以预览数据变化。* 能够保证数据的读一致性。数据库事务的应用数据库事务处理可分为隐式和显式两种。显式事务操作通过
15、命令实现,隐式事务由系统自动完成提交或撤销(回退) 工作,无需用户的干预。隐式提交的情况包括:当用户正常退出 SQL*Plus 或执行CREATE、DROP 、GRANT、REVOKE 等命令时会发生事务的自动提交。还有一种情况,如果把系统的环境变量 AUTOCOMMIT 设置为 ON(默认状态为OFF),则每当执行一条 INSERT、DELETE 或 UPDATE 命令对数据进行修改后,就会马上自动提交。设置命令格式如下:SET AUTOCOMMIT ON/OFF隐式回退的情况包括:当异常结束 SQL*Plus 或系统故障发生时,会发生事务的自动回退。显式事务处理的数据库事务操作语句有 3
16、条,语 句 描 述 COMIT 数 据 库 事 务 提 交 , 将 变 化 写 入 数 据 库 RLBACK 数 据 库 事 务 回 退 , 撤 销 对 数 据 的 修 改 SAVEPOINT 创 建 保 存 点 , 用 于 事 务 的 阶 段 回 退 COMMIT 操作把多个步骤对数据库的修改,一次性地永久写入数据库,代表数据库事务的成功执行。 ROLLBACK 操作在发生问题时,把对数据库已经作出的修改撤消,回退到修改前的状态。在操作过程中,一旦发生问题,如果还没有提交操作,则随时可以使用ROLLBACK 来撤消前面的操作。 SAVEPOINT 则用于在事务中间建立一些保存点,ROLLBA
17、CK 可以使操作回退到这些点上边,而不必撤销全部的操作。 一旦 COMMIT 完成,就不能用 ROLLBACK 来取消已经提交的操作。一旦ROLLBACK 完成,被撤消的操作要重做,必须重新执行相关操作语句。如何开始一个新的事务呢?一般情况下,开始一个会话(即连接数据库) ,执行第一条 SQL 语句将开始一个新的事务,或执行 COMMIT 提交或 ROLLBACK 撤销事务,也标志新的事务的开始。另外,执行DDL(如 CREATE)或 DCL 命令也将自动提交前一个事务而开始一个新的事务。只要进行了 insert update delete 等操作,养成好的习惯, commit 一下。注意:数
18、据在修改的时候会对记录进行锁定,其他会话不能对锁定的记录进行修改或加锁,只有当前会话提交或撤销后,记录的锁定才会释放。范例:为雇员 SCOTT 增加工资, SCOTT 的雇员号为 7788。学习使用 COMMIT 和ROLLBACK。步骤 1:执行以下命令,提交尚未提交的操作:COMMIT;显示 SCOTT 的现有工资:SELECT ename,sal FROM emp WHERE empno=7788;步骤 2:修改雇员 SCOTT 的工资:UPDATE emp SET sal=sal+100 WHERE empno=7788;步骤 3:假定修改操作后发现增加的工资应该为 1000 而不是
19、100,为了取消刚做的操作,可以执行以下命令:ROLLBACK;显示回退后 SCOTT 的工资恢复为 3000:SELECT ename,sal FROM emp WHERE empno=7788;步骤 4:重新修改雇员 SCOTT 的工资,工资在原有基础上增加 1000:UPDATE emp SET sal=sal+1000 WHERE empno=7788;显示修改后 SCOTT 的工资:SELECT ename,sal FROM emp WHERE empno=7788;步骤 5:经查看修改结果正确,提交所做的修改:COMMIT;说明:在执行 COMMIT 后,工资的修改被永久写入数据库
20、。本训练的第 1 步,先使用COMMIT 命令提交原来的操作,同时标志一个新的事务的开始。注意:在事务执行过程中,随时可以预览数据的变化。对于比较大的事务,可以使用 SAVEPOINT 命令在事务中间划分一些断点,用来作为回退点。范例:学习使用 SAVEPOINT 命令。步骤 1:插入一个雇员:INSERT INTO emp(empno, ename, job)VALUES (3000, 小马,STUDENT);步骤 2:插入保存点,检查点的名称为 PA:SAVEPOINT pa;步骤 3:插入另一个雇员:INSERT INTO emp(empno, ename, job)VALUES (30
21、01, 小黄,STUDENT);步骤 4:回退到保存点 PA,则后插入的小黄被取消,而小马仍然保留。ROLLBACK TO pa;步骤 5: 提交所做的修改:COMMIT;说明:第 4 步的回退,将回退到保存点 PA,即第 3 步被撤销。所以最后的 COMMIT 只提交了对小马的插入。请自行检查插入的雇员。练习:对 emp 表进行修改,然后退出 SQL*Plus,重新启动 SQL*Plus,检查所做的修改是否生效。在 Oracle 数据库中,有一个叫回滚段的特殊的存储区域。在提交一个事物之前,如果用户进行了数据的修改,在所谓的回滚段中将保存变化前的数据。有了回滚段才能在必要时使用 ROLLBA
22、CK 命令或自动地进行数据撤销。在提交事物之前,用户自己可以看到修改的数据,但因为修改还没有最终提交,其他用户看到的应该是原来的数据,也就是回滚段中的数据,这时用户自己看到的数据和其他用户看到的数据是不同的,只有提交发生后,变化的数据才会被写入数据库,此时用户自己看到的数据和其他用户看到的数据才是一致的,这叫做数据的读一致性。范例:观察数据的读一致性。步骤 1:显示刚插入的雇员小马:SELECT empno,ename FROM emp WHERE empno=3000;步骤 2:删除雇员小马:DELETE FROM emp WHERE empno=3000;步骤 3:再次显示该雇员,显示结果
23、为该雇员不存在:SELECT empno,ename FROM emp WHERE empno=3000;步骤 4:另外启动第 2 个 SQL*Plus,并以 SCOTT 身份连接。执行以下命令,结果为该记录依旧存在。SELECT empno,ename FROM emp WHERE empno=3000;步骤 5:在第 1 个 SQL*Plus 中提交删除:COMMIT;步骤 6:在第 2 个 SQL*Plus 中再次显示该雇员,显示结果与步骤 3 的结果一致:SELECT empno,ename FROM emp WHERE empno=3000;说明:在以上训练中,当第 1 个 SQL*
24、Plus 会话删除小马后,第 2 个 SQL*Plus 会话仍然可以看到该雇员,直到第 1 个 SQL*Plus 会话提交该删除操作后,两个会话看到的才是一致的数据。表的锁定(了解)锁的概念锁出现在数据共享的场合,用来保证数据的一致性。当多个会话同时修改一个表时,需要对数据进行相应的锁定。锁有“只读锁” 、 “排它锁 ”, “共享排它锁”等多种类型,而且每种类型又有 “行级锁”(一次锁住一条记录), “页级锁 ”(一次锁住一页,即数据库中存储记录的最小可分配单元),“表级锁”(锁住整个表)。 排它锁又称为写锁((Exclusive lock,简记为 X 锁)) ,若事务 T 对数据对象 A 加
25、上 X 锁,则只允许 T 读取和修改 A,其它任何事务都不能再对 A 加任何类型的锁,直到 T 释放A 上的锁。它防止任何其它事务 获取资源上的锁,直到在事务的末尾将资源上的原始锁释放为止。在更新操作(INSERT、UPDATE 或 DELETE)过程中始终应用排它锁。 共享锁又称为读锁(Share lock,简记为 S 锁) ,若事务 T 对数据对象 A 加上 S 锁,则其它事务只能再对 A 加 S 锁,而不能加 X 锁,直到 T 释放 A 上的 S 锁。 共享锁:由非更新(读取)操作创建的锁。其他用户可以并发读取数据,但任何事务都不能获取数据上的排它锁,直到已释放所有共享锁。 -|若为 “
26、行级排它锁” ,则除被锁住的行外,该表中其他行均可被其他的用户进行修改(Update)或删除 (delete)。-|若为 “表级排它锁” ,则所有其他用户只能对该表进行查询(select)操作,而无法对其中的任何记录进行修改或删除。当程序对所做的修改进行提交(commit)或回滚(rollback)后,锁住的资源便会得到释放,从而允许其他用户进行操作。-|有时,由于程序的原因,锁住资源后长时间未对其工作进行提交;或是由于用户的原因,调出需要修改的数据后,未及时修改并提交,而是放置于一旁;或是由于客户服务器方式中客户端出现“死机” ,而服务器端却并未检测到,从而造成锁定的资源未被及时释放,影响到
27、其他用户的操作。如果两个事务,分别锁定一部分数据,而都在等待对方释放锁才能完成事务操作,这种情况下就会发生死锁。隐式锁和显式锁在 Oracle 数据库中,修改数据操作时需要一个隐式的独占锁,以锁定修改的行,直到修改被提交或撤销为止。如果一个会话锁定了数据,那么第二个会话要想对数据进行修改,只能等到第一个会话对修改使用 COMMIT 命令进行提交或使用 ROLLBACK 命令进行回滚撤销后,才开始执行。因此应养成一个良好的习惯:执行修改操作后,要尽早地提交或撤销,以免影响其他会话对数据的修改。范例:对 emp 表的 SCOTT 雇员记录进行修改,测试隐式锁。步骤 1:启动第一个 SQL*Plus
28、,以 SCOTT 账户登录数据库( 第一个会话),修改 SCOTT 记录,隐式加锁。UPDATE emp SET sal=3500 where empno=7788;执行结果:已更新 1 行。步骤 2:启动第二个 SQL*Plus,以 SCOTT 账户登录数据库( 第二个会话),进行记录修改操作。UPDATE emp SET sal=4000 where empno=7788;执行结果,没有任何输出(处于等待解锁状态)。步骤 3:对第一个会话进行解锁操作:COMMIT;步骤 4:查看第二个会话,此时有输出结果:已更新 1 行。步骤 5:提交第二个会话,防止长时间锁定。说明:两个会话对同一表的同
29、一条记录进行修改。步骤 1 修改 SCOTT 工资为3500,没有提交或回滚之前,SCOTT 记录处于加锁状态。步骤 2 的第二个会话对 SCOTT进行修改处于等待状态。 步骤 3 解锁之后(即第一个会话对 SCOTT 的修改已经完成),第二个会话挂起的修改此时可以执行。最后结果为第二个会话的修改结果,即 SCOTT 的工资修改为 4000。读者可以使用查询语句检查。以上是隐式加锁,用户也可以使用如下两种方式主动锁定行或表,防止其他会话对数据的修改。表的显式锁定操作语句 语 句 描 述 SELCT FOR UPDATE 锁 定 表 行 , 防 止 其 他 会 话 对 行 的 修 改 OK AB
30、LE 锁 定 表 , 防 止 其 他 会 话 对 表 的 修 改 范例:对 emp 表的部门 10 的雇员记录加显式锁,并测试。步骤 1:对部门 10 加显式锁:SELECT empno,ename,job,sal FROM emp WHERE deptno=10 FOR UPDATE;步骤 2:启动第二个 SQL*Plus(第二个会话) ,以 SCOTT 账户登录数据库,对部门 10 的雇员 CLARK 进行修改操作。UPDATE emp SET sal=sal+100 where empno=7782;执行结果:没有任何输出(处于等待解锁状态)。步骤 3:在第一个会话进行解锁操作:COMM
31、IT;步骤 4:查看第二个会话,有输出结果:已更新 1 行。说明:步骤 1 对选定的部门 10 的雇员加锁,之后其他会话不能对部门 10 的雇员数据进行修改或删除。如果此时要进行修改或删除,则会处于等待状态。使用 COMMIT 语句进行解锁之后,如果有挂起的修改或删除操作,则等待的操作此时可以执行。练习:以数据库事务方式将 SCOTT 从 emp 表转入 manager 表,再将 SCOTT 的工资改成和emp 表的 KING 的工资一样。步骤 1:复制 emp 表的 SCOTT 到 manager 表:INSERT INTO manager SELECT empno,ename,sal FR
32、OM emp WHERE empno=7788;步骤 2:删除 emp 表的 SCOTT:DELETE FROM emp WHERE empno=7788;步骤 3:修改 SCOTT 的工资:UPDATE manager SET sal=(SELECT sal FROM emp WHERE empno=7839) WHERE empno=7788;步骤 4:提交:COMMIT;步骤 5:查询:SELECT * FROM manager WHERE empno=7788;说明:该训练中,SCOTT 的雇员编号为 7788,KING 的雇员编号为 7839。步骤 1 先将SCOTT 复制到 man
33、ager 表;步骤 2 删除原来的 SCOTT 记录;步骤 3 修改 SCOTT 的工资为 KING 的工资;步骤 4 进行一次性提交;通过步骤 5 的查询可以看到 SCOTT 已经移动到了 manager 表,其工资修改为 5100。表的创建和操作(重点)表由记录(行 row)和字段(列 column)构成,是数据库中存储数据的结构。要进行数据的存储和管理,首先要在数据库中创建表,即表的字段(列) 结构。有了正确的结构,就可以用数据操作命令,插入、删除表中记录或对记录进行修改。1创建表的语法表的创建需要 CREATE TABLE 系统权限,表的基本创建语法如下:CREATE TABLE 表名
34、(列名 数据类型(宽度)DEFAULT 表达式COLUMN CONSTRAINT,.TABLE CONSTRAINTTABLE_PARTITION_CLAUSE);说明:由此可见,创建表最主要的是要说明表名、列名、列的数据类型和宽度,多列之间用“, ”分隔。可以是用中文或英文作为表名和列名。表名最大长度为 30 个字符。在同一个用户下,表不能重名,但不同用户表的名称可以相重。另外,表的名称不能使用 Oracle 的保留字。在一张表中最多可以包含 2000 列。该语法中的其他部分根据需要添加,作用如下:DEFAULT 表达式:用来定义列的默认值。COLUMN CONSTRAINT:用来定义列级的
35、约束条件。TABLE CONSTRAINT:用来定义表级的约束条件。TABLE_PARTITION_CLAUSE:定义表的分区子句。范例:要进行图书管理,就需要创建图书和出版社等表,这里给出用于示范和训练的图书和出版社表的结构和内容。图书表: 图 书 编 号 图 书 名 称 出 版 社 编 号 作 者 出 版 日 期 数 量 单 价 A01 计 算 机 原 理 01 刘 勇 198年 5月 7日 8 25.30 02 C语 言 程 序 设 计 02 马 丽 203年 1月 2日 10 18.75 A03 汇 编 语 言 程 序 设 计 02 黄 海 明 201年 1月 5日 15 20.18
36、出版社表: 编 号 出 版 社 名 称 地 址 联 系 电 话 01 清 华 大 学 出 版 社 北 京 01-8345627 02 西 安 电 子 科 技 大 学 出 版 社 西 安 029-8201467 -创建出版社表CREATE TABLE 出版社(编号 VARCHAR2(2),出版社名称 VARCHAR2(30),地址 VARCHAR2(30),联系电话 VARCHAR2(20);-创建图书表CREATE TABLE 图书(图书编号 VARCHAR2(5),图书名称 VARCHAR2(30),出版社编号 VARCHAR2(2),作者 VARCHAR2(10),出版日期 DATE,数量
37、 NUMBER(3),单价 NUMBER(7,2);-使用DESCRIBE显示图书表的结构DESCRIBE 图书-使用DESCRIBE显示出版社表的结构DESCRIBE 出版社说明:列名和数据类型之间用空格分隔,数据类型后的括号中为宽度(日期类型除外) 。对于有小数的数字型,前一个参数为总宽度,后一个参数为小数位。用逗号分隔各列定义,但最后一列定义后不要加逗号。2通过子查询创建表如果要创建一个同已有的表结构相同或部分相同的表,可以采用以下的语法:CREATE TABLE 表名( 列名.) AS SQL 查询语句;该语法既可以复制表的结构,也可以复制表的内容,并可以为新表命名新的列名。新的列名在表名后的括号中给出,如果省略将采用原来表的列名。复制的内容由查询语句的 WHERE 条件决定。