不吐不快:
本来以为清华大学出版的书,质量上应该没的说,但是,通过调试示例程序,还是发现不少问题:
1. 个别概念解释不清,容易误导读者
2. 有些文字词不达意,不准确
3. 代码解释中有错别字,有的代码标题张冠李戴
之前说过的问题就不提了。总之,目前看到的最好的教材还是Java how to program,堪称完美!
代码如下:
--代码3.11 NUMBER类型声明示例 --说明:根据调试结果,基本可以确认Number(precesion,scale)中的precesion(精度)是指有效数字的位数,而不能简单理解为数字的长度。 --如,v_num6 NUMBER(4,-1):=31451;输出结果为31450,数字长度为5,而不是4(31450=3.145*10^1,科学计数法中的有效数字个数)。 --而另一参数-scale,意为赋值时小数点的移动位数,正数表示向右移动;负数表示向左移动 DECLARE v_num1 NUMBER:=3.1415926; --结果:3.1415926 v_num2 NUMBER(3):=3.1415926; --四舍五入等于3 --v_num2_1 NUMBER(3):=3145.1415926; --错误,精度太高:ORA-06502:PL/SQL:数字或值错误:数值精度太高 v_num3 NUMBER(4,3):=3.1415926; --结果:3.142 --v_num3_1 NUMBER(4,3):=314.123; --错误,精度太高:ORA-06502:PL/SQL:数字或值错误:数值精度太高 v_num4 NUMBER(8,3):=31415.9267; --四舍五入3位小数,结果为:31415.927 v_num5 NUMBER(4,-3):=3145611.789; --由于为负3,要小数点左侧进行舍入3位结果为3146000 v_num5_1 NUMBER(4,-3):=314.567895; --舍入后的结果为0 v_num6 NUMBER(4,-1):=31451; --舍入后结果31450 v_num6_1 NUMBER(4,-1):=3145123; --错误,精度太高:ORA-06502:PL/SQL:数字或值错误:数值精度太高 BEGIN DBMS_OUTPUT.put_line('v_num1:='||v_num1); DBMS_OUTPUT.put_line('v_num2:='||v_num2); DBMS_OUTPUT.put_line('v_num3:='||v_num3); DBMS_OUTPUT.put_line('v_num4:='||v_num4); DBMS_OUTPUT.put_line('v_num5:='||v_num5); DBMS_OUTPUT.put_line('v_num5_1:='||v_num5_1); DBMS_OUTPUT.put_line('v_num6:='||v_num6); -- DBMS_OUTPUT.put_line('v_num6_1:='||v_num6); END; --代码3.12 PLS_INTEGER与BINARY_INTEGER的使用示例 DECLARE v_num1 PLS_INTEGER :=2147483647; BEGIN --当为v_num1+1时,产生了溢出,会触发异常 v_num1:=v_num1+1-1; EXCEPTION WHEN OTHERS THEN --输出:ORA-01426: 数字溢出 DBMS_OUTPUT.put_line(SQLERRM); END; --BINARY_INTEGER使用示例 --实际调试结果:会产生编译错误 DECLARE v_num1 BINARY_INTEGER :=2147483647; BEGIN --以下论述与实际调试结果不符: --当为v_num1+1时,产生了溢出, --此时v_num1会被当作NUMBER进行处理,不会触发异常 v_num1:=v_num1+1-1; EXCEPTION WHEN OTHERS THEN --输出:ORA-01426: 数字溢出 DBMS_OUTPUT.put_line(SQLERRM); END; select power(2,8) from dual; select * from product_component_version; select * from v$instance; select * from V$VERSION --代码3.13 Date类型使用示例 --to_char函数中的'D'的含义,当前日期在本周中的天数序号,星期日为第一天(这个可不符合中国人的习惯啊? --Day of week (1-7). This element depends on the NLS territory of the session. DECLARE v_weekday DATE := trunc(SYSDATE) - to_char(SYSDATE, 'D') + 1; v_now DATE := SYSDATE; BEGIN dbms_output.put_line('上个星期天的日期为:'||to_char(v_weekday, 'yyyy-mm-dd')); dbms_output.put_line('当前时间:'||to_char(v_now, 'yyyy-mm-dd hh44:mi:ss')); END; --代码3.14 TIMESTAMP类型使用示例 DECLARE v_now TIMESTAMP(8) := SYSDATE; v_nowdate DATE := SYSDATE; BEGIN dbms_output.put_line(v_now); dbms_output.put_line(v_nowdate); END; --代码3.15 TIMESTATMP WITH TIME ZONE类型使用示例 DECLARE v_timestamp TIMESTAMP; --定义日期类型的变量 v_timestampwithzone TIMESTAMP WITH TIME ZONE; v_timestampwithlocalzone TIMESTAMP WITH LOCAL TIME ZONE; BEGIN v_timestamp := SYSDATE; --为日期类型的变量赋初值 v_timestampwithzone := SYSDATE; v_timestampwithlocalzone :=SYSDATE; DBMS_OUTPUT.put_line (v_timestamp); --输出信息 DBMS_OUTPUT.put_line (v_timestampwithzone); DBMS_OUTPUT.put_line ( v_timestampwithlocalzone); --和timestamp的输出相同 END; --INTERVAL YEAR TO MONTH类型使用示例 DECLARE v_start TIMESTAMP; --定义起始与结束时间戳类型 v_end TIMESTAMP; v_interval INTERVAL YEAR TO MONTH; v_year NUMBER; v_month NUMBER; v_date DATE; v_uinterv interval YEAR TO MONTH; BEGIN v_start := TO_TIMESTAMP('&v_date', 'yyyy-MM-dd'); --赋指定的时间戳值(此处优化了代码,允许用户任意输入一个日期(年月日,如2015-08-03)) v_end := CURRENT_TIMESTAMP; --赋当前的时间戳值 v_interval := (v_end - v_start) YEAR TO MONTH; --YEAR TO MONTH是INTERVAL表达式语法。 v_year := EXTRACT(YEAR FROM v_interval); --提取年份和月份 v_month := EXTRACT(MONTH FROM v_interval); --输出当前的INTERVAL类型的值 DBMS_OUTPUT.put_line(to_char(v_start, 'yyyy-mm-dd') || '与当前时间的间隔INTERVAL值为:' || v_interval); --输出年份与月份值 DBMS_OUTPUT.put_line('INTERVAL年份为:' || v_year || CHR(13) || CHR(10) || 'INTERVAL月份为:' || v_month); --直接为INTERVAL赋值 --此处增强代码,允许用户任意输入一个间隔(年月,如10年8个月,10-08),并计算经过该间隔定义的年月后的日期, --如,17年后,您的孩子上大学时,是哪一年呢?? --彩蛋:如何在英文输入法下,输入笑脸? --答案:1.打开Numlock开关(即小键盘/数字区) --2. 按住Alt的同时,在小键盘区域连续输入9786,?就会出现* v_interval := INTERVAL '&v_uinterv' YEAR TO MONTH; --输出INTERVAL的值 DBMS_OUTPUT.put_line('当前的INTERVAL值为:' || v_interval); v_year :=EXTRACT(YEAR FROM v_interval); v_month :=EXTRACT(month FROM v_interval); DBMS_OUTPUT.put_line(v_year||'年'||v_month||'月后的日期为:'||to_char((sysdate+v_interval),'yyyy-mm-dd')); v_interval := INTERVAL '01' YEAR; --直接为INTERVAL赋年份值 DBMS_OUTPUT.put_line('当前的INTERVAL值为:' || v_interval); --提取年份和月份 v_year := EXTRACT(YEAR FROM v_interval); v_month := EXTRACT(MONTH FROM v_interval); --输出值 DBMS_OUTPUT.put_line('INTERVAL年份为:' || v_year || CHR(13) || CHR(10) || 'INTERVAL月份为:' || v_month); v_interval := INTERVAL '03' MONTH; --直接为INTERVAL赋月份 --输出月份值 DBMS_OUTPUT.put_line('当前的INTERVAL值为:' || v_interval); END; --代码 3.17 布尔类型使用示例 DECLARE v_condition BOOLEAN; BEGIN v_condition := TRUE; -- v_condition := 'FALSE'; IF v_condition THEN dbms_output.put_line('布尔值为True'); END IF; END; --代码3.18 弱类型REF CURSOR使用示例 CREATE OR REPLACE FUNCTION selectallemployments RETURN sys_refcursor --定义一个返回sys_refcursor的函数 AS st_cursor sys_refcursor; BEGIN OPEN st_cursor FOR --使用该函数查询所有的员工记录 SELECT * FROM emp; --返回指向游标的指针 RETURN st_cursor; END; --代码3.19 使用引用游标示例 DECLARE x sys_refcursor; --定义引用游标变量 v_emp emp%ROWTYPE; --定义获取游标结果的记录类型 BEGIN x := selectallemployments;--调用函数获取游标指针 --循环遍历游标指针 LOOP FETCH x --提取游标数据 INTO v_emp; --当没有找到游标记录时则退出 EXIT WHEN x%NOTFOUND; --输出记录信息 DBMS_OUTPUT.put_line ( '员工编号:' || v_emp.empno || ' 员工名称:' || v_emp.ename ); END LOOP; END; --代码3.20 用户自定义类型示例 DECLARE SUBTYPE empcounttype IS INTEGER; empcount empcounttype; BEGIN SELECT COUNT(*) INTO empcount FROM emp; dbms_output.put_line('员工人数为:' || empcount); END;