其实DML只包含了以下3个语句:
INSERT
UPDATE
DELETE
INSERT语句
当往一个表中添加一行新的数据时,需要使用DML语言中的INSERT语句。该语句的格式如下:
INSERT INTO 表名 [(列名 [,列名…])]
VALUES(数值,数值…):
其中:
表名:要输入数据的表的名字。列名:表中要输入数据列的名字。数值:对应列的具体值。
使用以上的INSERT语句格式每一次只能向表中插入一行数据。例12-5的DML语句往dept_dml表中插入一行数据。例12-5
SQL> INSERT INTO dept_dml (deptno, dname, loc)
2 VALUES(66, '美容', '煤球胡同');
请注意在使用如例12-5的DML语句插入一行数据时,日期型和字符型的数据必须用单引号括起来。您可以在INSERTINTO子句中列出每一个要插入值的列的名字。其数值的数据类型一定与对应的列的数据类型相匹配。注意:
如果您在向某个表中插入中文字符时遇到了困难,不用着急。这很可能是在中文方式下输入引号或逗号造成的,您只要保证在英文方式下输入标点符号就应该没有问题了。
您也可以按表中列的默认顺序在VALUES子句中直接列出每一个要插入的数据值,而不用在INSERTINTO子句中列出每一个要插入值的列的名字,如例12-7.
例12-7
SQL> INSERT INTO dept_dml
2 VALUES(77,'订货','狼山市');
尽管使用例12-7所示的方法可以达到向一个表中插入一行数据的目的,但是在开发软件时应该列出所有要插入数据的列名,这样会使软件的易读性大为增加,也使软件更容易维护。
您可以在VALUES子句中使用空串('')向dept_DML表中输入一条含有空值(NULL)的记录,如例12-9的DML语句所示。
例12-9
SQL> INSERT INTO dept_DML(deptno, dname, loc)
2 VALUES(88, · · ·牛街');
也可以在VALUES子句中使用关键字NULL向dept_DML表中输入一条含有空值(NULL)的记录,如例12-11的DML语句所示。
例12-11
SQL> INSERT INTO dept_DML(deptno, dname, loc)
2 VALUES(44,NULL,'安静大街');
您还可以利用不列出要插入的列的方法向dept_DML表中输入一条含有空值(NULL)的记录,如例12-13的DML语句所示。
例12-13
SQL> INSERT INTO dept_DML(deptno, dname)
2 VALUES(33, 公关');
可以在插入语句中使用特殊的值。例如公司今天刚刚雇了一名新的保安,名字叫童铁蛋。现在经理让您将他的信息输入到员工表(emp_DML)中。很显然您没有必要在输入雇佣日期(hiredate)时再重新输入今天的日期,您完全可以使用Oracle提供的系统日期函数(SYSDATE)来输入今天的日期,如例12-16。
例12-16
SQL> INSERT INTO emp_DML(empno,ename,job,mgr,
2 hiredate,sal,comm,deptno)
3 VALUES (7800,'童铁蛋','保安',7900,SYSDATE,666,77,66);
12.5 如何利用子查询向表中插入数据
为了演示方便,首先我们使用如例12-20的SQL语句创建一个叫 sales的表。
例12-20
SQL> CREATE TABLE salee (code, name, salary, commission)
2 AS
3 SELECT empno,ename,sal,comm 4 FROM emp;
现在可以利用子查询向sales表中插入数据,如例12-23的INSERT语句。例12-23
SQL> INSERT INTO sales (code,name,salary,commission)
2 SELECT empno,ename,sal,comm
3 FROM emp
4 WHERE job LIKE 'SALE%';
在使用子查询向某个表中插入数据时不能使用VALUES关键字。
INSERT子句中的列数和数据类型必须与子查询中的列数和数据类型一致。
如何利用替代变量向表中插入数据和将 INSERT 语句存入脚本文件
如果只使用以上我们介绍的INSERT语句,很难开发出商用软件。因为在每次插入数
据时,我们都不得不重新改写VALUES子句中的值。向表中插入数据的另一个棘手的问题就是使用什么样的日期格式。如果选择的日期格式不合适的话,当数据库的字符集改变时,可能不得不重写所有选择使用的日期格式的程序。您可以在INSERT语句中使用SQL*PLUS的替代变量,这样Oracle就可以用交互的方式在SQL语句运行期间提示用户输入所需要列的值,如例12-25。
例12-25
SQL> INSERT INTO emp_DML(empno,ename,job,mgr,
2 hiredate, sal, comm, deptno)
3 VALUES (sid,'&name','&job',7689,
4 TO_DATE('shiredate','YYYY MM DD'),
5 666,77,66);
当运行例12-25的SQL语句时,Oracle系统会给出输入的提示,此时可以输入所需的数值。按回车键之后,Oracle系统就会显示已创建1行。这说明Oracle系统已成功地插入了您所输入的记录。
例12-25系统提示和输入输入id的值:1001 输入
name的值:王老五
输入job的值:保洁员
输入hiredate的值:20020708
利用ACCEPT在INSERT语句中产生用户友好的系统提示
虽然使用例12-25的SQL语句可以开发商用软件,但是它产生的系统提示信息不是很清楚,普通用户不太容易理解这些提示信息。您可以使用SQL*PLUS的ACCEPT命令重新粉饰一下12-25的SQL语句以便产生用户友好的系统提示信息。为此,可以使用例12-28 的SQL*PLUS命令来编辑刚刚创建的脚本文件d:\sql\insert.sql。
例12-28
SQL>edit d:\sql\insert.sql
ACCEPT id PROMPT '请输入员工的工号:
ACCEPT name PROMPT '请输入员工的名字:
ACCEPT job PROMPT 请输入员工的职位:
ACCEPT hiredate PROHPT “请输入员工的雇佣日期(如:2001 83 08);
IMSERT INTO emp_DML(empno,ename,job,ngr,
hiredate,sal,comm,deptno)
VALUES (&id,'&name','&job',7689, TO_DATE('Ghiredate','YYY MH DD'), 666,77,66)
UPDATE语句
例12-31
SQL> UPDATE emp_dml
2 SET sal=sal*0.9;
UPDATE语句的格式如下:
UPDATE 表名
SET 列名=值【,列名=值,…】
【WHERE 条件】:
其中:
表名:要修改数据的表的名字;
列名:表中要修改数据列的名字;
数值:对应列的具体值;
条件:由列名、表达式、常量、子查询和比较运算符组成,用来决定所要修改的数据行。
与INSERT语句不同,UPDATE语句可以一次修改多行记录。因此如果您要修改一条记录的话,在写UPDATE语句时就要保证一定只有一条记录能满足WHERE子句中的条件。为了解释这一点,我们在emp_dml中插入了另一名也叫童铁蛋的员工。不过他的职位、工资与前一个童铁蛋大不相同。下面使用例12-33查询语句来查看一下他们的信息。
从例 12-35 的结果可以清楚地看出,在 emp_dml 表中除了保安童铁蛋的工资被改为1000元之外,技术总监(CTO)的工资也被改为1000元。这显然是一个天大的笑话。之所以发生这种事情,是因为在 emp_dml表中员工的名字(ename)可以重名造成的。为了避免这类事情的发生,您应该保证WHERE子句中的条件能惟一地标识表中的一行。最稳妥的办法是使用主键(Primary Key)。
注意:|在使用UPDATE 语句来修改表中的记录时,如果WHERE子句中的条件写错了,就会造成该修改的记录没改而不该修改的记录都改了。如果忘写了WHERE子句,就会造成表中所有的记录都被修改。所以在使用 UPDATE 语句时要非常小心,一定要确保WHERE子句中的条件是正确的。
例12-36 SQL> SELECT
2 FROM salgrade;
salgrade表的第一列(GRADE)为职位的等级,第二列(LOSAL)为该级别的最低工资,第三列(HISAL)为该级别的最高工资。
例12-37
SQL> UPDATE emp_dml
2 SET sal = (SELECT losal
3 FROM salgrade
4 WHERE grade = 1)
5 WHERE sal<(SELECT losal
6 FROM salgrade
7 WHERE grade = 1);
在例12-37的UPDATE语句中,除了在WHERE子句中使用了子查询,您还在SET 子句中使用了子查询并把该子查询语句的返回值赋给了sal。
可以在 UPDATE 语句中利用基于另一个表的子查询来修改表中的记录。
例12-39
SQL> UPDATE emp_dml
2 SET (job,sal) = (SELECT job,sal
3 FROM emp_dml
4 WHERE empno = 7369)
5 WHERE job = '保安';
可以使用UPDATE语句来同时修改表中的多列。但是在使用这种方法时,在SET 子句中等号右边的必须是子查询语句。
DELETE语句
例12-41 SQL> SELECT *
2 FROM emp_dml
3 WHERE(job='MANAGER')OR(JOB= 'SALESMAN')
4 ORDER BY sal;
DELETE 语句用来删除一个表中存在的行。该语句的格式如下:
DELETE 【FROM】 表名
【WHERE 条件】;
其中:
表名:要从中删除数据的表名;
条件:由列名、表达式、常量、子查询和比较运算符组成,用来决定所要修改的数据行。
基于另一个表来删除行
例12-48
SQL> DELETE FROM emp_dml
2 WHERE deptno =
3 (SELECT deptno
4 FROM dept_dml
5 WHERE dname = UPPER('美容'));
为了有效地控制事务(Transactions),Oracle引入了两个显式的事务(Transactions)控制命令(语句),一个是COMMIT,另一个是ROLLBACK。
Oracle数据库的事务(Transactions)可由:■ 一个或多个DML语句组成。■ 一个DDL语句组成。■ 一个DCL语句组成。
那么如何标识一个事务(Transactions)呢?因为Oracle公司在开始时是瞄准联机事务处理(OLTP)的,所以它对事务处理提供了强有力的支持。Oracle可以自动地标识一个事务(Transactions)。
Oracle的一个事务是以第一个可执行的SQL语句开始,当下列事件之一发生时结束。(1)用户执行了COMMIT语句(提交)。(2)用户执行了ROLLBACK语句(回滚)。(3)用户执行了DDL语句(自动提交)。(4)用户执行了DCL语句(自动提交)。(5)用户正常退出SOL*PLUS(自动提交)。(6)用户非正常退出 SQL*PLUS(自动回滚)。(7)系统崩溃,包括硬件或软件故障(自动回滚)。
作为一位 Oracle 的专业人员,您应该尽可能地使用 COMMIT和 ROLLBACK 语句来显式地控制事务的提交和回滚。因为使用从3到7的隐式事务控制特性有时可能会产生意想不到的结果。现在我们可以使用这两个语句把12.14节中在银行的自动提款机(ATM)上那些逻辑上相关的操作集成为一个事务。这些逻辑上相关的操作要么全部完成(提交),要么全部放弃(回滚)。
Oracle数据库系统采取了另一种设计,即在有人对数据库中的数据进行写操作(即DML 操作)时,Oracle数据库系统允许其他的人对该数据进行读操作。这样就解决了上面所提到的问题。那么Oracle又是如何解决这一困难问题的呢?在每一个Oracle数据库中都有一个或多个叫回滚段的磁盘区(在Oracle9i之前的版本叫ROLLBACK SEGMENT,在Oracle9i 中叫UNDO SEGMENT)。当有人对数据库中的数据进行任何写操作(即DML操作)时,Oracle 数据库系统首先将原始的数据复制到回滚段中,之后才做相应的操作,在事务处理结束之前其他的用户可以读这些数据,但读的是回滚段上的数据。
Oracle 数据库系统的这一设计确实大大地提高了大型的商业数据库的效率,但这一设计也会产生数据的不一致,因为在同一时刻,同一个数据可能会有两个不同的值。不过在大多数商业机构中是可以容忍的。例如大公司在做年终结算(生成年报表)时差个千八百块钱也无所谓。另外公司可以用规章或规则来减缓这种数据的不一致。例如公司可以规定在做年报表或月报表时不允许进行任何 DML 操作,公司也可以规定要在下班之后做年报表或月报表。
在DML操作之前将原始数据复制到回滚段中这样的设计本身在某些情况下也会产生效率方面的问题。例如,在一个大型的商业数据库中数据库操作员在维护时使用DELETE 语句删除了一个一百万条记录的表。这样一个DML操作将要在回滚段上产生一百万条相同的记录项,这有可能会将回滚段所在的磁盘空间耗光造成Oracle数据库系统的挂起。因此如果要删除一个大表,为了数据库运行的效率,您可使用TRUNCATE语句而不用DELETE 语句,因为TRUNCATE 语句是DDL语句,不需要使用回滚段。