oracle ql/sql 相关语法解析
查询
SELECT语句用于从数据库中查询数据,当在PL/SQL中使用SELECT语句时,要与INTO子句一起使用,查询的
返回值被赋予INTO子句中的变量,变量的声明是在DELCARE中。SELECT INTO语法如下:
- SELECT [DISTICT|ALL]{*|column[,column,...]}
- INTO (variable[,variable,...] |record)
- FROM {table|(sub-query)}[alias]
- WHERE............
PL/SQL中SELECT语句只返回一行数据。如果超过一行数据,那么就要使用显式游标(对游标的讨论我们将
在后面进行),INTO子句中要有与SELECT子句中相同列数量的变量。INTO子句中也可以是记录变量。
%TYPE属性
在PL/SQL中可以将变量和常量声明为内建或用户定义的数据类型,以引用一个列名,同时继承他的数据类
型和大小。这种动态赋值方法是非常有用的,比如变量引用的列的数据类型和大小改变了,如果使用了%TYPE,
那么用户就不必修改代码,否则就必须修改代码。
例:
- v_empno SCOTT.EMP.EMPNO%TYPE;
- v_salary EMP.SALARY%TYPE;
不但列名可以使用%TYPE,而且变量、游标、记录,或声明的常量都可以使用%TYPE。这对于定义相同数据类
型的变量非常有用。
- DELCARE
- V_A NUMBER(5):=10;
- V_B V_A%TYPE:=15;
- V_C V_A%TYPE;
- BEGIN
- DBMS_OUTPUT.PUT_LINE
- ('V_A='||V_A||'V_B='||V_B||'V_C='||V_C);
- END
- SQL>/
- V_A=10 V_B=15 V_C=
- PL/SQL procedure successfully completed.
- SQL>
其他DML语句
其它操作数据的DML语句是:INSERT、UPDATE、DELETE和LOCK TABLE,这些语句在PL/SQL中的语法与在SQL中
的语法相同。我们在前面已经讨
论过DML语句的使用这里就不再重复了。在DML语句中可以使用任何在DECLARE部分声明的变量,如果是嵌套
块,那么要注意变量的作用范围。
例:
- 1 CREATE OR REPLACE PROCEDURE FIRE_EMPLOYEE (pempno in number)
- 2 AS
- 3 v_ename EMP.ENAME%TYPE;
- 4 BEGIN
- 5 SELECT ename INTO v_ename
- 6 FROM emp
- 7 WHERE empno=p_empno;
- 8 INSERT INTO FORMER_EMP(EMPNO,ENAME)
- 9 VALUES (p_empno,v_ename);
- 10 DELETE FROM emp
- 11 WHERE empno=p_empno;
- 12 UPDATE former_emp
- 13 SET date_deleted=SYSDATE
- 14 WHERE empno=p_empno;
- 15 EXCEPTION
- 16 WHEN NO_DATA_FOUND THEN
- 17 DBMS_OUTPUT.PUT_LINE('Employee Number Not Found!');
- 18 END
DML语句的结果
当执行一条DML语句后,DML语句的结果保存在四个游标属性中,这些属性用于控制程序流程或者了解程序
的状态。当运行DML语句时,PL/SQL打开一个内建游标并处理结果,游标是维护查询结果的内存中的一个区域,
游标在运行DML语句时打开,完成后关闭。隐式游标只使用SQL%FOUND,
SQL%NOTFOUND,SQL%ROWCOUNT三个属性.SQL%FOUND,SQL%NOTFOUND是布尔值,SQL%ROWCOUNT是整数值。
SQL%FOUND和SQL%NOTFOUND
在执行任何DML语句前SQL%FOUND和SQL%NOTFOUND的值都是NULL,在执行DML语句后,SQL%FOUND的属性值将是:
. TRUE :INSERT
. TRUE :DELETE和UPDATE,至少有一行被DELETE或UPDATE.
. TRUE :SELECT INTO至少返回一行
当SQL%FOUND为TRUE时,SQL%NOTFOUND为FALSE。
SQL%ROWCOUNT
在执行任何DML语句之前,SQL%ROWCOUNT的值都是NULL,对于SELECT INTO语句,如果执行成功
,SQL%ROWCOUNT的值为1,如果没有成功,SQL%ROWCOUNT的值为0,同时产生一个异常NO_DATA_FOUND.
SQL%ISOPEN
SQL%ISOPEN是一个布尔值,如果游标打开,则为TRUE, 如果游标关闭,则为FALSE.对于隐式游标而言SQL%
ISOPEN总是FALSE,这是因为隐式游
标在DML语句执行时打开,结束时就立即关闭。
事务控制语句
事务是一个工作的逻辑单元可以包括一个或多个DML语句,事物控制帮助用户保证数据的一致性。如果事务控制逻辑单元中的任何一个DML
语句失败,那么整个事务都将回滚,在PL/SQL中用户可以明确地使用COMMIT、ROLLBACK、SAVEPOINT以及
SET TRANSACTION语句。
COMMIT语句终止事务,永久保存数据库的变化,同时释放所有LOCK,ROLLBACK终止现行事务释放所有LOCK,
但不保存数据库的任何变化,SAVEPOI
NT用于设置中间点,当事务调用过多的数据库操作时,中间点是非常有用的,SET TRANSACTION用于设置事
务属性,比如read-write和隔离级等。
显式游标
查询返回结果超过一行时,就需要一个显式游标,此时用户不能使用select into语句。PL/SQL管理隐式
游标,当查询开始时隐式游标打开,查询结束时隐式游标自动关闭。显式游标在PL/SQL块的声明部分声明,在执行部分或异常处理部分打开,取数据,关闭。
使用游标
这里要做一个声明,我们所说的游标通常是指显式游标,因此从现在起没有特别指明的情况,我们所说的
游标都是指显式游标。要在程序中使用游标,必须首先声明游标。
声明游标
语法:
CURSOR cursor_name IS select_statement;
在PL/SQL中游标名是一个未声明变量,不能给游标名赋值或用于表达式中。
例:
- DELCARE
- CURSOR C_EMP IS SELECT empno,ename,salary
- FROM emp
- WHERE salary>2000
- ORDER BY ename;
- ........
- BEGIN
在游标定义中SELECT语句中不一定非要表可以是视图,也可以从多个表或视图中选择的列,甚至可以使用*
来选择所有的列 。
打开游标
使用游标中的值之前应该首先打开游标,打开游标初始化查询处理。打开游标的语法是:
- OPEN cursor_name
cursor_name是在声明部分定义的游标名。
例:
- OPEN C_EMP;
关闭游标
语法:
- CLOSE cursor_name
例:
- CLOSE C_EMP;
从游标提取数据
从游标得到一行数据使用FETCH命令。每一次提取数据后,游标都指向结果集的下一行。语法如下:
FETCH cursor_name INTO variable[,variable,...]
对于SELECT定义的游标的每一列,FETCH变量列表都应该有一个变量与之相对应,变量的类型也要相同。
例:
- 1 SET SERVERIUTPUT ON
- 2 DECLARE
- 3 v_ename EMP.ENAME%TYPE;
- 4 v_salary EMP.SALARY%TYPE;
- 5 CURSOR c_emp IS SELECT ename,salary FROM emp;
- 6 BEGIN
- 7 OPEN c_emp;
- 8 FETCH c_emp INTO v_ename,v_salary;
- 9 DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
- 10 FETCH c_emp INTO v_ename,v_salary;
- 11 DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
- 12 FETCH c_emp INTO v_ename,v_salary;
- 13 DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
- 14 CLOSE c_emp;
- 15 END
这段代码无疑是非常麻烦的,如果有多行返回结果,可以使用循环并用游标属性为结束循环的条件,以这
种方式提取数据,程序的可读性和简洁性都大为提高,下面我们使用循环重新写上面的程序:
- 1 SET SERVERIUTPUT ON
- 2 DECLARE
- 3 v_ename EMP.ENAME%TYPE;
- 4 v_salary EMP.SALARY%TYPE;
- 5 CURSOR c_emp IS SELECT ename,salary FROM emp;
- 6 BEGIN
- 7 OPEN c_emp;
- 8 LOOP
- 9 FETCH c_emp INTO v_ename,v_salary;
- 10 EXIT WHEN c_emp%NOTFOUND;
- 11 DBMS_OUTPUT.PUT_LINE('Salary of Employee'|| v_ename ||'is'|| v_salary);
- 12 END
记录变量
定义一个记录变量使用TYPE命令和%ROWTYPE,关于%ROWsTYPE的更多信息请参阅相关资料。
记录变量用于从游标中提取数据行,当游标选择很多列的时候,那么使用记录比为每列声明一个变量要方
便得多。
当在表上使用%ROWTYPE并将从游标中取出的值放入记录中时,如果要选择表中所有列,那么在SELECT子句
中使用*比将所有列名列出来要安全得多。
例:
- 1 SET SERVERIUTPUT ON
- 2 DECLARE
- 3 R_emp EMP%ROWTYPE;
- 4 CURSOR c_emp IS SELECT * FROM emp;
- 5 BEGIN
- 6 OPEN c_emp;
- 7 LOOP
- 8 FETCH c_emp INTO r_emp;
- 9 EXIT WHEN c_emp%NOTFOUND;
- 10 DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
- 11 END LOOP;
- 12 CLOSE c_emp;
- 13 END;
%ROWTYPE也可以用游标名来定义,这样的话就必须要首先声明游标:
- SET SERVERIUTPUT ON
- DECLARE
- CURSOR c_emp IS SELECT ename,salary FROM emp;
- R_emp c_emp%ROWTYPE;
- BEGIN
- OPEN c_emp;
- LOOP
- FETCH c_emp INTO r_emp;
- EXIT WHEN c_emp%NOTFOUND;
- DBMS_OUT.PUT.PUT_LINE('Salary of Employee'||r_emp.ename||'is'|| r_emp.salary);
- END LOOP;
- CLOSE c_emp;
- END;
带参数的游标
与存储过程和函数相似,可以将参数传递给游标并在查询中使用。这对于处理在某种条件下打开游标的情
况非常有用。它的语法如下:
CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
定义参数的语法如下:
Parameter_name [IN] data_type[{:=|DEFAULT} value]
与存储过程不同的是,游标只能接受传递的值,而不能返回值。参数只定义数据类型,没有大小。
另外可以给参数设定一个缺省值,当没有参数值传递给游标时,就使用缺省值。游标中定义的参数只是一个占位符,在别处引用该参数不一定可靠。
在打开游标时给参数赋值,语法如下:
OPEN cursor_name[value[,value]....];
参数值可以是文字或变量。
例:
- 1 DECALRE
- 2 CURSOR c_dept IS SELECT * FROM dept ORDER BY deptno;
- 3 CURSOR c_emp (p_dept VARACHAR2) IS
- 4 SELECT ename,salary
- 5 FROM emp
- 6 WHERE deptno=p_dept
- 7 ORDER BY ename
- 8 r_dept DEPT%ROWTYPE;
- 9 v_ename EMP.ENAME%TYPE;
- 10 v_salary EMP.SALARY%TYPE;
- 11 v_tot_salary EMP.SALARY%TYPE;
- 12 BEGIN
- 13 OPEN c_dept;
- 14 LOOP
- 15 FETCH c_dept INTO r_dept;
- 16 EXIT WHEN c_dept%NOTFOUND;
- 17 DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
- 18 v_tot_salary:=0;
- 19 OPEN c_emp(r_dept.deptno);
- 20 LOOP
- 21 FETCH c_emp INTO v_ename,v_salary;
- 22 EXIT WHEN c_emp%NOTFOUND;
- 23 DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
- 24 v_tot_salary:=v_tot_salary+v_salary;
- 25 END LOOP;
- 26 CLOSE c_emp;
- 27 DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
- 28 END LOOP;
- 29 CLOSE c_dept;
- 30 END;
游标FOR循环
在大多数时候我们在设计程序的时候都遵循下面的步骤:
1、打开游标
2、开始循环
3、从游标中取值
4、检查那一行被返回
5、处理
6、关闭循环
7、关闭游标
可以简单的把这一类代码称为游标用于循环。但还有一种循环与这种类型不相同,这就是FOR循环,用于
FOR循环的游标按照正常的声明方式声明,它的优点在于不需要显式的打开、关闭、取数据,测试数据的存在、定义存放数据的变量等等。
游标FOR循环的语法如下:
- FOR record_name IN
- (corsor_name[(parameter[,parameter]...)]
- | (query_difinition)
- LOOP
- statements
- END LOOP;
下面我们用for循环重写上面的例子:
- 1 DECALRE
- 2 CURSOR c_dept IS SELECT deptno,dname FROM dept ORDER BY deptno;
- 3 CURSOR c_emp (p_dept VARACHAR2) IS
- 4 SELECT ename,salary
- 5 FROM emp
- 6 WHERE deptno=p_dept
- 7 ORDER BY ename
- 8 v_tot_salary EMP.SALARY%TYPE;
- 9 BEGIN
- 10 FOR r_dept IN c_dept LOOP
- 11 DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
- 12 v_tot_salary:=0;
- 13 FOR r_emp IN c_emp(r_dept.deptno) LOOP
- 14 DBMS_OUTPUT.PUT_LINE('Name:' || v_ename || 'salary:' || v_salary);
- 15 v_tot_salary:=v_tot_salary+v_salary;
- 16 END LOOP;
- 17 DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
- 18 END LOOP;
- 19 END;
在游标FOR循环中使用查询
在游标FOR循环中可以定义查询,由于没有显式声明所以游标没有名字,记录名通过游标查询来定义。
- 1 DECALRE
- 2 v_tot_salary EMP.SALARY%TYPE;
- 3 BEGIN
- 4 FOR r_dept IN (SELECT deptno,dname FROM dept ORDER BY deptno) LOOP
- 5 DBMS_OUTPUT.PUT_LINE('Department:'|| r_dept.deptno||'-'||r_dept.dname);
- 6 v_tot_salary:=0;
- 7 FOR r_emp IN (SELECT ename,salary
- 8 FROM emp
- 9 WHERE deptno=p_dept
- 10 ORDER BY ename) LOOP
- 11 DBMS_OUTPUT.PUT_LINE('Name:'|| v_ename||' salary:'||v_salary);
- 12 v_tot_salary:=v_tot_salary+v_salary;
- 13 END LOOP;
- 14 DBMS_OUTPUT.PUT_LINE('Toltal Salary for dept:'|| v_tot_salary);
- 15 END LOOP;
- 16 END;
游标中的子查询
语法如下:
- CURSOR C1 IS SELECT * FROM emp
- WHERE deptno NOT IN (SELECT deptno
- FROM dept
- WHERE dname!='ACCOUNTING');
可以看出与SQL中的子查询没有什么区别。
游标中的更新和删除
在PL/SQL中依然可以使用UPDATE和DELETE语句更新或删除数据行。显式游标只有在需要获得多行数据的情
况下使用。PL/SQL提供了仅仅使 用游标就可以执行删除或更新记录的方法。
UPDATE或DELETE语句中的WHERE CURRENT OF子串专门处理要执行UPDATE或DELETE操作的表中取出的最近的
数据。要使用这个方法,在声明游标 时必须使用FOR UPDATE子串,当对话使用FOR UPDATE子串打开一个游标时,所有返回集中的数据行都将处于行级(ROW-LEVEL)独占式锁定,其
他对象只能查询这些数据行,不能进行UPDATE、DELETE或SELECT...FOR UPDATE操作。
语法:
FOR UPDATE [OF [schema.]table.column[,[schema.]table.column]..
[nowait]
在多表查询中,使用OF子句来锁定特定的表,如果忽略了OF子句,那么所有表中选择的数据行都将被锁定。
如果这些数据行已经被其他会话锁定,那么正常情况下ORACLE将等待,直到数据行解锁。
在UPDATE和DELETE中使用WHERE CURRENT OF子串的语法如下:
WHERE{CURRENT OF cursor_name|search_condition}
例:
- 1 DELCARE
- 2 CURSOR c1 IS SELECT empno,salary
- 3 FROM emp
- 4 WHERE comm IS NULL
- 5 FOR UPDATE OF comm;
- 6 v_comm NUMBER(10,2);
- 7 BEGIN
- 8 FOR r1 IN c1 LOOP
- 9 IF r1.salary<500 THEN
- 10 v_comm:=r1.salary*0.25;
- 11 ELSEIF r1.salary<1000 THEN
- 12 v_comm:=r1.salary*0.20;
- 13 ELSEIF r1.salary<3000 THEN
- 14 v_comm:=r1.salary*0.15;
- 15 ELSE
- 16 v_comm:=r1.salary*0.12;
- 17 END IF;
- 18 UPDATE emp;
- 19 SET comm=v_comm
- 20 WHERE CURRENT OF c1l;
- 21 END LOOP;
- 22 END
- -声明游标
- --宗地表的调查日期LANDINFO_RESEARCHDATE
- --复制到流程表的权属调查时间FLOW_REASEARCHTIME
- 1 DECLARE
- 2 cursor cur_sel_all is select LANDINFO_RESEARCHDATE,LANDINFO_LANDNO from t_leoa_landinfo; --定义游标
- 3 l_date t_leoa_landinfo.landinfo_researchdate%type; --声明变量分别保存t_leoa_landinfo的各列
- 4 l_landNo t_leoa_landinfo.landinfo_landno%type;
- 5 begin
- 6 open cur_sel_all;
- 7 loop --循环取数,并将游标数据填充到返回纪录集合中
- 8 fetch cur_sel_all into l_date,l_landNo;
- 9 exit when cur_sel_all%NOTFOUND; --循环退出条件
- 10 if cur_sel_all%FOUND then --获取数据
- 11 update T_LEOA_BOOKFLOW t2 set FLOW_REASEARCHTIME = l_date where l_landNo = t2.landinfo_landno;
- 12 end if;
- 13 end loop;
- 14 close cur_sel_all;
- 15 end;
下面再分享一下另外一则游标使用方法的代码,具体如下:
- 1 -- 声明游标;CURSOR cursor_name IS select_statement
- 2 --For 循环游标
- 3 --(1)定义游标
- 4 --(2)定义游标变量
- 5 --(3)使用for循环来使用这个游标
- 6 declare
- 7 --类型定义
- 8 cursor c_job
- 9 is
- 10 select empno,ename,job,sal
- 11 from emp
- 12 where job='MANAGER';
- 13 --定义一个游标变量v_cinfo c_emp%ROWTYPE ,该类型为游标c_emp中的一行数据类型
- 14 c_row c_job%rowtype;
- 15 begin
- 16 for c_row in c_job loop
- 17 dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
- 18 end loop;
- 19 end;
- 20 --Fetch游标
- 21 --使用的时候必须要明确的打开和关闭
- 22 declare
- 23 --类型定义
- 24 cursor c_job
- 25 is
- 26 select empno,ename,job,sal
- 27 from emp
- 28 where job='MANAGER';
- 29 --定义一个游标变量
- 30 c_row c_job%rowtype;
- 31 begin
- 32 open c_job;
- 33 loop
- 34 --提取一行数据到c_row
- 35 fetch c_job into c_row;
- 36 --判读是否提取到值,没取到值就退出
- 37 --取到值c_job%notfound 是false
- 38 --取不到值c_job%notfound 是true
- 39 exit when c_job%notfound;
- 40 dbms_output.put_line(c_row.empno||'-'||c_row.ename||'-'||c_row.job||'-'||c_row.sal);
- 41 end loop;
- 42 --关闭游标
- 43 close c_job;
- 44 end;
- 1 --1:任意执行一个update操作,用隐式游标sql的属性%found,%notfound,%rowcount,%isopen观察update语句的执行情况。
- 2 begin
- 3 update emp set ENAME='ALEARK' WHERE EMPNO=7469;
- 4 if sql%isopen then
- 5 dbms_output.put_line('Openging');
- 6 else
- 7 dbms_output.put_line('closing');
- 8 end if;
- 9 if sql%found then
- 10 dbms_output.put_line('游标指向了有效行');--判断游标是否指向有效行
- 11 else
- 12 dbms_output.put_line('Sorry');
- 13 end if;
- 14 if sql%notfound then
- 15 dbms_output.put_line('Also Sorry');
- 16 else
- 17 dbms_output.put_line('Haha');
- 18 end if;
- 19 dbms_output.put_line(sql%rowcount);
- 20 exception
- 21 when no_data_found then
- 22 dbms_output.put_line('Sorry No data');
- 23 when too_many_rows then
- 24 dbms_output.put_line('Too Many rows');
- 25 end;
- 26 declare
- 27 empNumber emp.EMPNO%TYPE;
- 28 empName emp.ENAME%TYPE;
- 29 begin
- 30 if sql%isopen then
- 31 dbms_output.put_line('Cursor is opinging');
- 32 else
- 33 dbms_output.put_line('Cursor is Close');
- 34 end if;
- 35 if sql%notfound then
- 36 dbms_output.put_line('No Value');
- 37 else
- 38 dbms_output.put_line(empNumber);
- 39 end if;
- 40 dbms_output.put_line(sql%rowcount);
- 41 dbms_output.put_line('-------------');
- 42 select EMPNO,ENAME into empNumber,empName from emp where EMPNO=7499;
- 43 dbms_output.put_line(sql%rowcount);
- 44 if sql%isopen then
- 45 dbms_output.put_line('Cursor is opinging');
- 46 else
- 47 dbms_output.put_line('Cursor is Closing');
- 48 end if;
- 49 if sql%notfound then
- 50 dbms_output.put_line('No Value');
- 51 else
- 52 dbms_output.put_line(empNumber);
- 53 end if;
- 54 exception
- 55 when no_data_found then
- 56 dbms_output.put_line('No Value');
- 57 when too_many_rows then
- 58 dbms_output.put_line('too many rows');
- 59 end;
- --2,使用游标和loop循环来显示所有部门的名称
- --游标声明
- declare
- cursor csr_dept
- is
- --select语句
- select DNAME
- from Depth;
- --指定行指针,这句话应该是指定和csr_dept行类型相同的变量
- row_dept csr_dept%rowtype;
- begin
- --for循环
- for row_dept in csr_dept loop
- dbms_output.put_line('部门名称:'||row_dept.DNAME);
- end loop;
- end;
- 1 --3,使用游标和while循环来显示所有部门的的地理位置(用%found属性)
- 2 declare
- 3 --游标声明
- 4 cursor csr_TestWhile
- 5 is
- 6 --select语句
- 7 select LOC
- 8 from Depth;
- 9 --指定行指针
- 10 row_loc csr_TestWhile%rowtype;
- 11 begin
- 12 --打开游标
- 13 open csr_TestWhile;
- 14 --给第一行喂数据
- 15 fetch csr_TestWhile into row_loc;
- 16 --测试是否有数据,并执行循环
- 17 while csr_TestWhile%found loop
- 18 dbms_output.put_line('部门地点:'||row_loc.LOC);
- 19 --给下一行喂数据
- 20 fetch csr_TestWhile into row_loc;
- 21 end loop;
- 22 close csr_TestWhile;
- 23 end;
- 24 select * from emp
- 1 --4,接收用户输入的部门编号,用for循环和游标,打印出此部门的所有雇员的所有信息(使用循环游标)
- 2 --CURSOR cursor_name[(parameter[,parameter],...)] IS select_statement;
- 3 --定义参数的语法如下:Parameter_name [IN] data_type[{:=|DEFAULT} value]
- 4 declare
- 5 CURSOR
- 6 c_dept(p_deptNo number)
- 7 is
- 8 select * from emp where emp.depno=p_deptNo;
- 9 r_emp emp%rowtype;
- 10 begin
- 11 for r_emp in c_dept(20) loop
- 12 dbms_output.put_line('员工号:'||r_emp.EMPNO||'员工名:'||r_emp.ENAME||'工资:'||r_emp.SAL);
- 13 end loop;
- 14 end;
- 15 select * from emp
- 16 --5:向游标传递一个工种,显示此工种的所有雇员的所有信息(使用参数游标)
- 17 declare
- 18 cursor
- 19 c_job(p_job nvarchar2)
- 20 is
- 21 select * from emp where JOB=p_job;
- 22 r_job emp%rowtype;
- 23 begin
- 24 for r_job in c_job('CLERK') loop
- 25 dbms_output.put_line('员工号'||r_job.EMPNO||' '||'员工姓名'||r_job.ENAME);
- 26 end loop;
- 27 end;
- 28 SELECT * FROM EMP
- 29 --6:用更新游标来为雇员加佣金:(用if实现,创建一个与emp表一摸一样的emp1表,对emp1表进行修改操作),并将更新前后的数据输出出来
- 30 --http://zheng12tian.iteye.com/blog/815770
- 31 create table emp1 as select * from emp;
- 32 declare
- 33 cursor
- 34 csr_Update
- 35 is
- 36 select * from emp1 for update OF SAL;
- 37 empInfo csr_Update%rowtype;
- 38 saleInfo emp1.SAL%TYPE;
- 39 begin
- 40 FOR empInfo IN csr_Update LOOP
- 41 IF empInfo.SAL<1500 THEN
- 42 saleInfo:=empInfo.SAL*1.2;
- 43 elsif empInfo.SAL<2000 THEN
- 44 saleInfo:=empInfo.SAL*1.5;
- 45 elsif empInfo.SAL<3000 THEN
- 46 saleInfo:=empInfo.SAL*2;
- 47 END IF;
- 48 UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_Update;
- 49 END LOOP;
- 50 END;
- 51 --7:编写一个PL/SQL程序块,对名字以‘A'或‘S'开始的所有雇员按他们的基本薪水(sal)的10%给他们加薪(对emp1表进行修改操作)
- 52 declare
- 53 cursor
- 54 csr_AddSal
- 55 is
- 56 select * from emp1 where ENAME LIKE 'A%' OR ENAME LIKE 'S%' for update OF SAL;
- 57 r_AddSal csr_AddSal%rowtype;
- 58 saleInfo emp1.SAL%TYPE;
- 59 begin
- 60 for r_AddSal in csr_AddSal loop
- 61 dbms_output.put_line(r_AddSal.ENAME||'原来的工资:'||r_AddSal.SAL);
- 62 saleInfo:=r_AddSal.SAL*1.1;
- 63 UPDATE emp1 SET SAL=saleInfo WHERE CURRENT OF csr_AddSal;
- 64 end loop;
- 65 end;
- 66 --8:编写一个PL/SQL程序块,对所有的salesman增加佣金(comm)500
- 67 declare
- 68 cursor
- 69 csr_AddComm(p_job nvarchar2)
- 70 is
- 71 select * from emp1 where JOB=p_job FOR UPDATE OF COMM;
- 72 r_AddComm emp1%rowtype;
- 73 commInfo emp1.comm%type;
- 74 begin
- 75 for r_AddComm in csr_AddComm('SALESMAN') LOOP
- 76 commInfo:=r_AddComm.COMM+500;
- 77 UPDATE EMP1 SET COMM=commInfo where CURRENT OF csr_AddComm;
- 78 END LOOP;
- 79 END;
- 80 --9:编写一个PL/SQL程序块,以提升2个资格最老的职员为MANAGER(工作时间越长,资格越老)
- 81 --(提示:可以定义一个变量作为计数器控制游标只提取两条数据;也可以在声明游标的时候把雇员中资格最老的两个人查出来放到游标中。)
- 82 declare
- 83 cursor crs_testComput
- 84 is
- 85 select * from emp1 order by HIREDATE asc;
- 86 --计数器
- 87 top_two number:=2;
- 88 r_testComput crs_testComput%rowtype;
- 89 begin
- 90 open crs_testComput;
- 91 FETCH crs_testComput INTO r_testComput;
- 92 while top_two>0 loop
- 93 dbms_output.put_line('员工姓名:'||r_testComput.ENAME||' 工作时间:'||r_testComput.HIREDATE);
- 94 --计速器减一
- 95 top_two:=top_two-1;
- 96 FETCH crs_testComput INTO r_testComput;
- 97 end loop;
- 98 close crs_testComput;
- 99 end;
- 100 --10:编写一个PL/SQL程序块,对所有雇员按他们的基本薪水(sal)的20%为他们加薪,
- 101 --如果增加的薪水大于300就取消加薪(对emp1表进行修改操作,并将更新前后的数据输出出来)
- 102 declare
- 103 cursor
- 104 crs_UpadateSal
- 105 is
- 106 select * from emp1 for update of SAL;
- 107 r_UpdateSal crs_UpadateSal%rowtype;
- 108 salAdd emp1.sal%type;
- 109 salInfo emp1.sal%type;
- 110 begin
- 111 for r_UpdateSal in crs_UpadateSal loop
- 112 salAdd:= r_UpdateSal.SAL*0.2;
- 113 if salAdd>300 then
- 114 salInfo:=r_UpdateSal.SAL;
- 115 dbms_output.put_line(r_UpdateSal.ENAME||': 加薪失败。'||'薪水维持在:'||r_UpdateSal.SAL);
- 116 else
- 117 salInfo:=r_UpdateSal.SAL+salAdd;
- 118 dbms_output.put_line(r_UpdateSal.ENAME||': 加薪成功.'||'薪水变为:'||salInfo);
- 119 end if;
- 120 update emp1 set SAL=salInfo where current of crs_UpadateSal;
- 121 end loop;
- 122 end;
- 123 --11:将每位员工工作了多少年零多少月零多少天输出出来
- 124 --近似
- 125 --CEIL(n)函数:取大于等于数值n的最小整数
- 126 --FLOOR(n)函数:取小于等于数值n的最大整数
- 127 --truc的用法 http://publish.it168.com/2005/1028/20051028034101.shtml
- 128 declare
- 129 cursor
- 130 crs_WorkDay
- 131 is
- 132 select ENAME,HIREDATE, trunc(months_between(sysdate, hiredate) / 12) AS SPANDYEARS,
- 133 trunc(mod(months_between(sysdate, hiredate), 12)) AS months,
- 134 trunc(mod(mod(sysdate - hiredate, 365), 12)) as days
- 135 from emp1;
- 136 r_WorkDay crs_WorkDay%rowtype;
- 137 begin
- 138 for r_WorkDay in crs_WorkDay loop
- 139 dbms_output.put_line(r_WorkDay.ENAME||'已经工作了'||r_WorkDay.SPANDYEARS||'年,零'||r_WorkDay.months||'月,零'||r_WorkDay.days||'天');
- 140 end loop;
- 141 end;
- 142 --12:输入部门编号,按照下列加薪比例执行(用CASE实现,创建一个emp1表,修改emp1表的数据),并将更新前后的数据输出出来
- 143 -- deptno raise(%)
- 144 -- 10 5%
- 145 -- 20 10%
- 146 -- 30 15%
- 147 -- 40 20%
- 148 -- 加薪比例以现有的sal为标准
- 149 --CASE expr WHEN comparison_expr THEN return_expr
- 150 --[, WHEN comparison_expr THEN return_expr]... [ELSE else_expr] END
- 151 declare
- 152 cursor
- 153 crs_caseTest
- 154 is
- 155 select * from emp1 for update of SAL;
- 156 r_caseTest crs_caseTest%rowtype;
- 157 salInfo emp1.sal%type;
- 158 begin
- 159 for r_caseTest in crs_caseTest loop
- 160 case
- 161 when r_caseTest.DEPNO=10
- 162 THEN salInfo:=r_caseTest.SAL*1.05;
- 163 when r_caseTest.DEPNO=20
- 164 THEN salInfo:=r_caseTest.SAL*1.1;
- 165 when r_caseTest.DEPNO=30
- 166 THEN salInfo:=r_caseTest.SAL*1.15;
- 167 when r_caseTest.DEPNO=40
- 168 THEN salInfo:=r_caseTest.SAL*1.2;
- 169 end case;
- 170 update emp1 set SAL=salInfo where current of crs_caseTest;
- 171 end loop;
- 172 end;
- 173 --13:对每位员工的薪水进行判断,如果该员工薪水高于其所在部门的平均薪水,则将其薪水减50元,输出更新前后的薪水,员工姓名,所在部门编号。
- 174 --AVG([distinct|all] expr) over (analytic_clause)
- 175 ---作用:
- 176 --按照analytic_clause中的规则求分组平均值。
- 177 --分析函数语法:
- 178 --FUNCTION_NAME(<argument>,<argument>...)
- 179 --OVER
- 180 --(<Partition-Clause><Order-by-Clause><Windowing Clause>)
- 181 --PARTITION子句
- 182 --按照表达式分区(就是分组),如果省略了分区子句,则全部的结果集被看作是一个单一的组
- 183 select * from emp1
- 184 DECLARE
- 185 CURSOR
- 186 crs_testAvg
- 187 IS
- 188 select EMPNO,ENAME,JOB,SAL,DEPNO,AVG(SAL) OVER (PARTITION BY DEPNO ) AS DEP_AVG
- 189 FROM EMP1 for update of SAL;
- 190 r_testAvg crs_testAvg%rowtype;
- 191 salInfo emp1.sal%type;
- 192 begin
- 193 for r_testAvg in crs_testAvg loop
- 194 if r_testAvg.SAL>r_testAvg.DEP_AVG then
- 195 salInfo:=r_testAvg.SAL-50;
- 196 end if;
- 197 update emp1 set SAL=salInfo where current of crs_testAvg;
- 198 end loop;
- 199 end;
oracle ql/sql 相关语法解析的更多相关文章
- Oracle使用Sql把XML解析成表(Table)的方法
SELECT * FROM XMLTABLE('$B/DEAL_BASIC/USER_DEAL_INFO' PASSING XMLTYPE('<?xml version="1.0&qu ...
- ORACLE之SQL语句内部解析过程【weber出品】
一.客户端通过监听连接到数据库,数据库开启一个server process进程来接收客户端传过来的sql. 1.这条sql语句从来都没有被执行过.(硬解析) 2.这条sql语句被执行过.(软解析) 二 ...
- ORACLE与SQL SERVER语法区别
一.数据类型 ORACLE与SQL SERVER在数据类型的对比如下: SQL SERVER ORACLE 数字类型 DECIMAL[(P[, S])] NUMBER[(P[, S])] NUMERI ...
- Oracle PL/SQL入门语法点
PL_SQL:带有分支和循环,面向过程匿名块:declare(可选,声明各种变量和游标的地方)begin(必要的,从此开始执行)exception(抓取到异常后执行的)end;[sql] view p ...
- Oracle中sql相关的命令
1.创建用户 SQL> -- 例如创建一个用户名为xiaoming,密码为a123的用户 SQL> create user xiaomingidentified by a123; 用户已创 ...
- Oracle PL/SQL编程语法
--plsql块结构,计算a,b的和 declare a ; b ; c int; begin c:=a+b; dbms_output.put_line(c); end; --%type数据类型,输出 ...
- Oracle sql执行计划解析
Oracle sql执行计划解析 https://blog.csdn.net/xybelieve1990/article/details/50562963 Oracle优化器 Oracle的优化器共有 ...
- Oracle HS (Heterogeneous Services)深入解析 及协同Gateway工作流程(转)
异构的数据源同Oracle Database做交互原理. 图1 上图是一张Oracle 异构连接处理的架构图,其中我们可以看到主要的非数据源模块包括有HS(Heterogeneous Service) ...
- Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python
Atitit.sql ast 表达式 语法树 语法 解析原理与实现 java php c#.net js python 1.1. Sql语法树 ast 如下图锁死1 2. SQL语句解析的思路和过程3 ...
随机推荐
- Ubuntu16.04+Tensorflow+CUDA9.0+cuDNN7.0 环境简明搭建指南
最近在研究风格化得内容,发现搭建环境实在是很头疼的事情,虽然网上已经有各路大神总结整理好了很多搭建指南,各种问题的解决方案都已经罗列出来供大家参考.然后参考终究是参考,真正自己上手,发现仍旧是各种坑, ...
- 使用JWT登录生成token
package com.example.demo.util; import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import co ...
- jQurey轮播插件slides简单使用教程
动态演示地址: http://www.zqunyan.com/zgproduction/slidesjs/index.html 简介就不多说了,网上有很多,复制粘贴没意义,会想到用这个插件就代表已经了 ...
- 03 . Docker数据资源管理与网络
Docker数据卷 在容器中管理数据主要有两种方式 # 数据卷(Data volumes) # 数据卷容器(Data volume containers) # 数据卷是一个可供一个或多个容器使用的特殊 ...
- 085 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 04 构造方法调用
085 01 Android 零基础入门 02 Java面向对象 01 Java面向对象基础 02 构造方法介绍 04 构造方法调用 本文知识点:构造方法调用 说明:因为时间紧张,本人写博客过程中只是 ...
- 解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact
解决mvn clean install的报错The packaging for this project did not assign a file to the build artifact
- ansible-playbook文件结构
ansible-playbook文件结构: 1 --- 2 - name: play1 #指定的playbook名字 3 hosts: webservers #指定主机组 4 remote_user: ...
- 使用Python对植物大战僵尸学习研究
根据上一篇 使用Python读写游戏1 中,使用Python win32库,对一款游戏进行了读内存 操作. 今天来写一下对内存进行写的操作 正文 要进行32位的读写,首先了解一下要用到的几个函数,通过 ...
- day38 Pyhton 并发编程
# 网络编程 # arp协议 : # 1.这是一个通过ip找mac地址的协议 # 2.由于有了socket,用户在使用网络的时候,只需要关心对方用户的ip地址就可以了 # 3.如果用户即将和这个ip进 ...
- Spring Boot 系列:日志动态配置详解
世界上最快的捷径,就是脚踏实地,本文已收录架构技术专栏关注这个喜欢分享的地方. 开源项目: 分布式监控(Gitee GVP最有价值开源项目 ):https://gitee.com/sanjianket ...