一篇详尽的Oracle常见语句记录~~不断补充
数据导出
exp account/password@dbname file=D:\your_path.dmp
基操
# 系统管理员身份登录
sys as sysdba
# 删除用户下所有数据
drop user 用户名 cascade;
# 创建用户
create user 用户名 identified by 密码;
# 用户授权
grant dba to 用户名;
# 修改密码
alter user 用户名 identified by 新密码;
# 创建表空间:
CREATE TABLESPACE 表空间名称 LOGGING DATAFILE '路径\表空间文件名称.dbf' SIZE 6114M AUTOEXTEND ON NEXT 32M MAXSIZE 8192M EXTENT MANAGEMENT LOCAL;
# 将空间分配给用户:
alter user 用户名 default tablespace 表空间名称;
# 把表空间授权给用户:
grant create session,create table,unlimited tablespace to 用户名;
# 查找用户
select * from dba_users;
# 查找工作空间的路径
select * from dba_data_files;
# 查看当前数据库连接数
select count(*) from v$process;
# 查看数据库最大连接数
select value from v$parameter where name = 'processes'
# 修改数据库连接数【修改完后需要重启数据库服务使其生效】
alter system set processes = 300 scope = spfile;
# 查看表结构
desc tablename;
导出数据库表Excel
SELECT t1.Table_Name || chr(13) AS "表名称及说明",
--t3.comments AS "表说明",
t1.Column_Name AS "字段名称",
t1.DATA_TYPE || '(' || t1.DATA_LENGTH || ')' AS "数据类型",
t1.NullAble AS "是否为空",
t2.Comments AS "字段说明",
t1.Data_Default "默认值"
--t4.created AS "建表时间"
FROM cols t1
LEFT JOIN user_col_comments t2
ON t1.Table_name = t2.Table_name
AND t1.Column_Name = t2.Column_Name
LEFT JOIN user_tab_comments t3
ON t1.Table_name = t3.Table_name
LEFT JOIN user_objects t4
ON t1.table_name = t4.OBJECT_NAME
WHERE NOT EXISTS(SELECT t4.Object_Name
FROM User_objects t4
WHERE t4.Object_Type = 'TABLE'
AND t4.Temporary = 'Y'
AND t4.Object_Name = t1.Table_Name)
ORDER BY t1.Table_Name, t1.Column_ID;
常见函数
日期函数
函数 |
说明 |
ADD_MONTHS(date, n) |
用于从一个日期值增加或减少 |
MONTHS_BETWEEN(date1, date2) |
判断两个日期之间相差的月份 |
LAST_DAY(date) |
函数返回包含日期的月份的最后一天 |
ROUND(date[,'fmt']) |
将日期d按照fmt指定的格式舍入,fmt为字符串 |
TRUNC(date[,'fmt']) |
返回由fmt指定格式的日期 |
NEXT_DAY(date,'char') |
找到下一个星期几 |
extract(date_field from [datetime_value]) |
找出日期或间隔值的字段值 |
日期函数示例
SELECT ADD_MONTHS(SYSDATE, 12) AS NEXT_YEAR FROM DUAL;
>> 2020/10/23 11:39:11
SELECT MONTHS_BETWEEN(TO_DATE('2020/10/23', 'yyyy/mm/dd'), SYSDATE) AS MONTHS FROM DUAL;
>> 12
SELECT LAST_DAY(SYSDATE) AS LAST_DAY FROM DUAL;
>> 2019/10/31 11:39:11
SELECT ROUND(SYSDATE, 'MONTH') AS MONTH FROM DUAL;
>> 2019/11/1
SELECT TRUNC(SYSDATE, 'YYYY') FROM DUAL;
>> 2019/1/1
SELECT NEXT_DAY(SYSDATE, '星期五') FROM DUAL;
>> 2019/10/25 11:39:11
SELECT EXTRACT(MONTH FROM SYSDATE) AS MONTH FROM DUAL;
>> 10
字符函数
函数 |
说明 |
INITCAP('char') |
字符串首字母大写 |
LOWER('char') |
字符串小写 |
UPPER('char') |
字符串大写 |
LTRIM('char',set) |
从左边开始去掉与set相同的字符 |
RTRIM('char',set) |
从右边开始去掉与set相同的字符 |
TRANSLATE(str, from_str,to_str) |
字符替换,from及to字符个数要相等 |
REPLACE(str,from_str,to_str) |
字符替换,from及to字符个数可不相等 |
INSTR(str,char,m,n) |
从m位置开始寻找第n个str字符(串)(m,n缺省为1) |
SUBSTR(str,m,n) |
截取从m位置开始至第n之间的字符串 |
CONCAT(str1,str2) |
拼接str1与str2字符串 |
字符函数示例
SELECT INITCAP('hello') FROM DUAL;
>> Hello
SELECT LOWER('HELLO') FROM DUAL;
>> hello
SELECT UPPER('hello') FROM DUAL;
>> HELLO
SELECT LTRIM('HELLO WORLD', 'HELLPO') FROM DUAL;
>> WORLD
SELECT RTRIM('HELLO WORLD', 'WORLD') FROM DUAL;
>> HELLO
SELECT TRANSLATE('HELLO BILL', 'B', 'TI') FROM DUAL;
>> HELLO TILL
SELECT REPLACE('HELLO BILL', 'B', 'TI') FROM DUAL;
>> HELLO TIILL
SELECT INSTR('HELLO','E') FROM DUAL;
>> 2
SELECT SUBSTR('HELLO WORLD', 7, 5) FROM DUAL;
>> WORLD
SELECT CONCAT('HELLO',' WORLD') FROM DUAL;
>> HELLO WORLD
其他字符函数
函数 |
说明 |
CHR(int) |
输出对应ascii码的字符 |
ASCII(char) |
输出对应字符的ascii码 |
LPAD(str1,int,str2) |
整个字符串长度等于int的情况下,在str1左边插入str2 |
RPAD(str1,int,str2) |
整个字符串长度等于int的情况下,在str1右边插入str2 |
TRIM([leading/trailing/both] [匹配字符串或数值] FROM [待处理字符串或数值]) |
去掉符合要求的字符 |
LENGTH(str) |
取字符串长度 |
DECODE |
当指定字段的值满足条件时,输出对应结果 |
其他字符函数示例
SELECT CHR(65) FROM DUAL;
>> A
SELECT ASCII('A') FROM DUAL;
>> 65
SELECT LPAD('ABCDE', 10, 'W') FROM DUAL;
>> WWWWWABCDE
SELECT RPAD('ABCDE', 10, 'W') FROM DUAL;
>> ABCDEWWWWW
SELECT TRIM('A' FROM 'ABCDEA') FROM DUAL;
>> BCDE
SELECT TRIM(LEADING 'A' FROM 'ABCADEA') FROM DUAL;
>> BCADEA
SELECT TRIM(TRAILING 'A' FROM 'ABCADEA') FROM DUAL;
>> ABCADE
SELECT TRIM(BOTH 'A' FROM 'ABCADEA') FROM DUAL;
>> BCADE
SELECT LENGTH('ABCDE') FROM DUAL;
>> 5
SELECT TU.ID,TU.NAME,TU.AGE,
DECODE(TU.AGE, 20, '青年',
30, '中年',
40, '中老年') AS AGE_STAGE
FROM T_USER TU;
>> ID NAME AGE AGE_STAGE
1 张三 20 青年
2 李四 30 中年
3 王五 40 中老年
数字函数
函数 |
说明 |
ABS(x) |
此函数用来返回一个数的绝对值 |
CEIL(x) |
用来返回大于或等于X的最小整数 |
COS(x) |
返回x的余弦值。x是以弧度表示的角度 |
COSH(x) |
返回X的双曲余弦 |
FLOOR(x) |
用来返回小于或等于X的最大整数 |
POWER(x,y) |
返回X的Y次幂。底X和指数Y都不必是正整数,但如果X是负数的话,Y必须是整数 |
MOD(被除数,除数)求余 |
如果除数为0,则返回被除数 |
ROUND(x[,y]) |
返回舍入到小数点右边Y位的X值。Y缺省为0,这将X舍入为最接近的整数。如果Y是负数, 那么舍入到小数点左边相应的位上,Y必须为整数 |
TRUNC(x[,y])截取值 |
Y缺省为0,这样X被截取成一个整数。如果Y为负数,那么截取到小数点左边相应位置 |
SQRT(x) |
返回x的平方根,x不能是负数 |
SIGN(x) |
此函数用来返回一个数的正负值,若为一个正数则返回1,若为一个负数则返回-1,若为0则仍返回0,有点像把模拟量数字化的意思 |
数字函数示例
SELECT ABS(-100) AS RESULT FROM DUAL;
>> 100
SELECT CEIL(100.001) AS RESULT FROM DUAL;
>> 101
SELECT COS(180) AS RESULT FROM DUAL;
>> -0.598460069057858
SELECT COSH(180) AS RESULT FROM DUAL;
>> 7.44692100390919E77
SELECT FLOOR(100.001) AS RESULT FROM DUAL;
>> 100
SELECT POWER(2,3) AS RESULT FROM DUAL;
>> 8
SELECT MOD(10,3) AS RESULT FROM DUAL;
>> 1
SELECT ROUND(100.0456, 3) AS RESULT FROM DUAL;
>> 100.046
SELECT TRUNC(100.0456, -1) AS RESULT FROM DUAL;
>> 100
SELECT SQRT(100) AS RESULT FROM DUAL;
>> 10
SELECT SIGN(-100) AS RESULT FROM DUAL;
>> -1
转换函数
函数 |
说明 |
TO_CHAR |
转换字符 |
TO_DATE |
转换日期 |
TO_NUMBER |
转换数字 |
转换函数示例
SELECT TO_CHAR(10000, 'C99,999') AS RESULT FROM DUAL;
>> CNY10,000
SELECT TO_CHAR(10000, 'L99,999') AS RESULT FROM DUAL;
>> ¥10,000
SELECT TO_CHAR(10000, 'S99,999') AS RESULT FROM DUAL;
>> +10,000
SELECT TO_CHAR(10000, 'U99,999') AS RESULT FROM DUAL;
>> ¥10,000
SELECT TO_CHAR(10000, '$99,999') AS RESULT FROM DUAL;
>> $10,000
SELECT TO_DATE('2019-10-23', 'YYYY-MM-DD') AS RESULT FROM DUAL;
>> 2019/10/23
SELECT TO_DATE('2019-10-23 15:00:01', 'YYYY-MM-DD HH24:MI:SS') AS RESULT FROM DUAL;
>> 2019/10/23 15:00:01
SELECT TO_NUMBER('10000') AS RESULT FROM DUAL;
>> 10000
其他函数
函数 |
说明 |
NVL(exp1,exp2) |
如果exp1对应的值为空,用exp2值替代 |
NVL2(exp1,exp2,exp3) |
如果exp1为空,取exp2;如果exp1不为空,取exp3 |
NULLIF(exp1,exp2) |
如果exp1与exp2相等,相等返回null,不相等返回exp1 |
其他函数示例
SELECT ID,NAME,SAL,NVL(COMM,0) AS COMM,NVL(COMM,0)+SAL AS INCOME FROM T_EMP;
>> 1 张三 1000 500 1500
2 王五 2000 2000 4000
3 张三 3000 500 3500
4 李娜 4000 0 4000
5 刘二 5000 1000 6000
SELECT ID,NAME,SAL,NVL(COMM,0) AS COMM,NVL2(COMM,COMM+SAL,SAL) AS INCOME FROM T_EMP;
>> 1 张三 1000 500 1500
2 王五 2000 2000 4000
3 张三 3000 500 3500
4 李娜 4000 0 4000
5 刘二 5000 1000 6000
SELECT ID,NAME,SAL,NVL(COMM,0) AS COMM,NULLIF(SAL,COMM) AS RESULT FROM T_EMP;
>> 1 张三 1000 500 1000
2 王五 2000 2000
3 张三 3000 500 3000
4 李娜 4000 0 4000
5 刘二 5000 1000 5000
分组函数
函数 |
说明 |
AVG |
求平均数 |
SUM |
求和 |
MIN |
求最小数 |
MAX |
求最大数 |
COUNT |
求行数 |
GROUP BY |
分组函数 |
HAVING |
分组时的过滤条件 |
分组函数示例
SELECT AVG(SAL) AS SAL_AVG FROM T_EMP;
>> 3000
SELECT SUM(SAL) AS SAL_SUM FROM T_EMP;
>> 15000
SELECT MIN(SAL) AS SAL_MIN FROM T_EMP;
>> 1000
SELECT MAX(SAL) AS SAL_MAX FROM T_EMP;
>> 5000
SELECT COUNT(*) AS EMP_COUNT FROM T_EMP;
>> 5
SELECT COMM,COUNT(COMM) FROM T_EMP GROUP BY COMM;
>> 0
1000 1
500 2
2000 1
SELECT COMM,COUNT(COMM) FROM T_EMP GROUP BY COMM HAVING COMM > 0;
>> 1000 1
500 2
2000 1
分析函数
函数 |
说明 |
ROW_NUMBER |
返回连续的排位,不论值是否相等 |
RANK |
具有相等值的行排位相同,序数随后跳跃 |
DENSE_RANK |
具有相等值的行排位相同,序号是连续的 |
分析函数示例
SELECT ROW_NUMBER() OVER (ORDER BY SAL DESC) AS SEAIL,NAME,SAL,COMM FROM T_EMP;
>> SEAIL NAME SAL COMM
1 刘二 5000 1000
2 李娜 4000
3 王五 2000 2000
4 张三 2000 500
5 张三 1000 500
SELECT RANK() OVER (PARTITION BY NAME ORDER BY SAL DESC,COMM) AS SEAIL,NAME,SAL,COMM FROM T_EMP;
>> SEAIL NAME SAL COMM
1 刘二 5000 1000
1 张三 2000 500
2 张三 1000 500
1 李娜 4000
1 王五 2000 2000
SELECT DENSE_RANK() OVER (PARTITION BY NAME ORDER BY SAL DESC,COMM) AS SEAIL,NAME,SAL,COMM FROM T_EMP;
PL/SQL编程
PL/SQL块
DECLARE
code
BEGIN
-- statements
EXCEPITON
code
END;
PROCEDURE name IS
BEGIN
-- statements
EXCEPTION
code
END;
FUNCTION name RETURN datatype IS
BEGIN
-- statements
RETURN value;
EXCEPTION
code
END;
控制结构
语句 |
说明 |
IF-THEN |
一种情况,条件满足就执行 |
IF-THEN-ELSE |
两种情况,条件满不满足都能执行对应的部分 |
IF-THEN-ELSIF |
多种情况,执行满足条件的部分 |
CASE-WHEN-ELSE |
多种情况,执行满足条件的部分 |
-- 查询comm字段值为空的sal,当sal=4000时,设置comm为1000
declare
-- 定义number类型的变量V_SAL
V_SAL NUMBER;
begin
-- 查询COMM为空的SAL,赋值给V_SAL
SELECT T.SAL INTO V_SAL FROM T_EMP T WHERE T.COMM IS NULL;
-- 判断V_SAL的值为4000时
IF V_SAL = 4000 THEN
-- 更新COMM的值为1000
UPDATE T_EMP T SET T.COMM = 1000 WHERE T.SAL = V_SAL;
-- 提交事务
COMMIT;
-- 打印提示
DBMS_OUTPUT.put_line('奖金已设置成:1000');
ELSE
UPDATE T_EMP T SET T.COMM = 2000 WHERE T.SAL = V_SAL;
DBMS_OUTPUT.put_line('奖金已设置成:2000');
END IF;
end;
语句 |
说明 |
LOOP |
无条件循环 |
WHILE |
根据条件循环 |
FOR |
循环固定次数 |
-- LOOP示例:循环插入初始化数据
DECLARE
-- 定义初始化值得变量
I INT:=5;
BEGIN
-- 开始循环
LOOP
-- 插入数据
INSERT INTO T_EMP(ID,NAME,SAL,COMM) VALUES (I, 'NAME'||I, I*1000, I*500);
-- 当i=20时退出循环
EXIT WHEN I = 20;
-- 每次循环完成后i+1
I:=I+1;
-- 结束循环
END LOOP;
END;
--------------------------------------------------------------------------------------------------
-- WHILE示例:循环插入初始化数据
DECLARE
-- 定义初始化值得变量
I INT:=1;
BEGIN
-- 开始循环,到20结束
WHILE I < 21 LOOP
-- 插入数据
INSERT INTO T_EMP(ID,NAME,SAL,COMM) VALUES (I, 'NAME'||I, I*1000, I*500);
-- 每次循环完成后i+1
I:=I+1;
-- 结束循环
END LOOP;
END;
--------------------------------------------------------------------------------------------------
-- FOR示例:循环插入初始化数据
DECLARE
-- 定义初始化值得变量
I INT:=1;
BEGIN
-- 开始循环,1到20结束(正序)
FOR I IN 1..20 LOOP
-- 插入数据
INSERT INTO T_EMP(ID,NAME,SAL,COMM) VALUES (I, 'NAME'||I, I*1000, I*500);
-- 结束循环
END LOOP;
END;
--------------------------------------------------------------------------------------------------
-- FOR示例:循环插入初始化数据
BEGIN
-- 开始循环,到20结束
FOR I IN REVERSE 1..20 LOOP
-- 插入数据
INSERT INTO T_EMP(ID,NAME,SAL,COMM) VALUES (I, 'NAME'||I, I*1000, I*500);
-- 结束循环
END LOOP;
END;
语句 |
说明 |
GOTO |
无条件的转到标签指定的语句 |
NULL |
什么也不做的空语句 |
-- GOTO & NULL示例:如果表数据为空的话,循环插入初始化数据
DECLARE
V_COUNT INT;
BEGIN
SELECT COUNT(*) INTO V_COUNT FROM T_EMP;
IF V_COUNT = 0 THEN
-- 跳转到INSERT_DATA标签下的代码块
GOTO INSERT_DATA;
ELSE
-- 跳转到INSERT_END标签下的代码块
GOTO INSERT_END;
END IF;
-- 定义标签 INSERT_DATA
<<INSERT_DATA>>
-- 开始循环,到20结束
FOR I IN REVERSE 1..20 LOOP
-- 插入数据
INSERT INTO T_EMP(ID,NAME,SAL,COMM) VALUES (I, 'NAME'||I, I*1000, I*500);
-- 结束循环
END LOOP;
-- 定义标签 INSERT_END
<<INSERT_END>>
NULL;
END;
异常处理
异常名 |
说明 |
NO_DATA_FOUND |
执行查询无数据、引用一个末初使化的表、通过UTL_FILE包调用到尾的文件 |
TOO_MANY_ROWS |
采用SELECT INTO语句,但返回的记录超过了1条 |
DUP_VAL_ON_INDEX |
插入或者更新语句,与唯一索引相冲突 |
TIMEOUT_ON_RESOURCE |
等待资源超时 |
TRANSACTION_BACKED_OUT |
远程交易的部份交易已经回滚 |
INVALID_CURSOR |
引用一个不存在的游标,如FETCH或者是CLOSE在其OPEN之前等 |
NOT_LOGGED_ON |
在登陆ORACLE之前执行调用错误 |
LOGIN_DENIED |
登陆时用户名或者密码非法 |
ZERO_DIVIDE |
0为除数 |
INVALID_NUMBER |
将字符串转换成数字,但是转换失败 |
STORAGE_ERROR |
内存不足 |
PROGRAM_ERROR |
系统自身程序错误 |
VALUE_ERROR |
在执行转换、截断、非法转换数据到文本出错 |
CURSOR_ALREADY_OPEN |
打开一个已经打开的游标 |
-- 异常处理
DECLARE
-- 定义变量
V_NAME T_EMP.NAME%TYPE;
BEGIN
-- 查询符合条件的name
SELECT T.NAME INTO V_NAME FROM T_EMP T WHERE T.NAME = '张三';
-- 输出结果
DBMS_OUTPUT.put_line(V_NAME);
-- 异常处理
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line('用户不存在');
END;
-- 异常处理
DECLARE
-- 定义变量
V_NAME T_EMP.NAME%TYPE;
ERR EXCEPTION;
BEGIN
-- 查询符合条件的name
SELECT DISTINCT T.NAME INTO V_NAME FROM T_EMP T WHERE T.SAL = 10000;
IF V_NAME = 'NAME10' THEN
-- 跳转
RAISE ERR;
END IF;
-- 输出结果
DBMS_OUTPUT.put_line(V_NAME);
-- 异常处理
EXCEPTION
WHEN ERR THEN
DBMS_OUTPUT.put_line('正确进入到了异常处理块中!');
END;
游标

游标说明图
游标类型
隐式游标:任何SQL都是,PLSQL程序中执行DML语句时自动创建。
显式游标:手动创建,用于处理返回多行查询。
REF游标:用户处理运行时才能确定的动态SQL查询的结果。
属性 |
说明 |
SQL%FOUND |
SQL语句影响了一行或多行时为true |
SQL%NOTFOUND |
SQL语句没有影响任何行为时为true |
SQL%ROWCOUNT |
SQL语句影响的行数 |
SQL%ISOPEN |
游标是否打开,始终为false |
/* NOTFOUND使用: */
DECLARE
FLAG CHAR:='U';
BEGIN
UPDATE T_EMP T SET T.NAME = '张三' WHERE T.SAL = 2000;
/* 隐式游标 */
IF SQL%NOTFOUND THEN
FLAG := 'Z';
INSERT INTO T_EMP (ID, NAME, SAL, COMM) VALUES ('21', '张三', 10000, 0);
END IF;
IF FLAG = 'U' THEN
DBMS_OUTPUT.PUT_LINE('记录已更改!');
ELSIF FLAG = 'Z' THEN
DBMS_OUTPUT.PUT_LINE('记录未找到,新插入成功!');
ELSE
DBMS_OUTPUT.PUT_LINE('SQL执行失败!');
END IF;
END;
-------------------------------------------------------------------------------------
/* ROWCOUNT使用: */
create or replace FUNCTION MYTESTFUNCTION
(
V_COMM IN NUMBER
) RETURN VARCHAR2 AS
BEGIN
IF V_COMM IS NULL THEN RETURN '请输入奖金';
ELSE
UPDATE T_EMP T SET T.SAL = 20000 WHERE T.COMM = V_COMM;
IF SQL%ROWCOUNT > 0 THEN
RETURN '修改了'||SQL%ROWCOUNT||'条数据';
ELSE
RETURN '没有修改数据!';
END IF;
END IF;
RETURN NULL;
END MYTESTFUNCTION;
使用方式 |
说明 |
CURSOR…IS SELECT… |
声明游标 |
OPEN |
打开游标 |
FETCH...INTO... |
结果集控制 |
CLOSE |
关闭游标 |
DECLARE
-- 定义游标 MYCUR
CURSOR MYCUR IS SELECT * FROM T_EMP;
V_EMP T_EMP%ROWTYPE;
BEGIN
-- 打开游标
OPEN MYCUR;
-- 提取游标
FETCH MYCUR INTO V_EMP;
-- 循环
WHILE MYCUR%FOUND LOOP
-- 输出内容
DBMS_OUTPUT.PUT_LINE(V_EMP.NAME||' '||V_EMP.SAL||' '||V_EMP.COMM);
-- 提取游标下一个内容
FETCH MYCUR INTO V_EMP;
END LOOP;
-- 关闭游标
CLOSE MYCUR;
END;
DECLARE
CURSOR MYCUR(V_COMM NUMBER) IS SELECT * FROM T_EMP WHERE COMM = V_COMM;
BEGIN
-- 循环游标
FOR V_EMP IN MYCUR('2000') LOOP
DBMS_OUTPUT.PUT_LINE(V_EMP.NAME);
END LOOP;
END;
类型 |
语法 |
强类型 |
TYPE my_curtype IS REF CURSOR RETURN stu_det%ROWTYPE; my_cur my_curtype; |
弱类型 |
TYPE my_curtype IS REF CURSOR; my_cur my_curtype; |
OPEN cursor_name FOR select_statement;
DECLARE
-- 定义弱类型游标
TYPE cursor_type IS REF CURSOR;
stu_cursor cursor_type;
v_emp t_emp%rowtype;
BEGIN
-- 打开游标,指定数据集
OPEN stu_cursor FOR SELECT * FROM t_emp;
-- 循环游标
LOOP
FETCH stu_cursor INTO v_emp;
EXIT WHEN stu_cursor%notfound;
dbms_output.put_line(v_emp.NAME || ' ' || v_emp.comm);
END LOOP;
-- 关闭游标
CLOSE stu_cursor;
END;
语法 |
OPEN cursor_name FOR dynamic_sqlstring [USING bind_arg_list]; |
-- 查找薪水大于5000的员工信息
DECLARE
TYPE cursor_type IS REF CURSOR;
emp_cursor cursor_type;
v_emp t_emp%rowtype;
-- 定义动态变量
v_sal t_emp.sal%TYPE;
BEGIN
-- 给变量赋值
v_sal := 5000;
-- 在SQL中定义 :1 ,使用using插入值
OPEN emp_cursor FOR
'select * from t_emp where sal>:1 order by sal desc'
USING v_sal;
dbms_output.put_line('姓名 薪水 奖金');
LOOP
FETCH emp_cursor INTO v_emp;
EXIT WHEN emp_cursor%notfound;
dbms_output.put_line(v_emp.NAME || ' ' || v_emp.sal || ' ' || v_emp.comm);
END LOOP;
CLOSE emp_cursor;
END;
--------------------------------------------------------------------------------------
-- 查找薪水大于5000的员工信息
DECLARE
TYPE cursor_type IS REF CURSOR;
emp_cursor cursor_type;
v_name t_emp.NAME%TYPE;
v_sal t_emp.sal%TYPE;
v_comm t_emp.sal%TYPE;
-- 定义动态变量
s_sal t_emp.sal%TYPE;
BEGIN
-- 给变量赋值
s_sal := 5000;
-- 在SQL中定义 :1 ,使用using插入值
OPEN emp_cursor FOR
'select name,sal,comm from t_emp where sal>:1 order by sal desc'
USING s_sal;
dbms_output.put_line('姓名 薪水 奖金');
LOOP
FETCH emp_cursor INTO v_name,v_sal,v_comm;
EXIT WHEN emp_cursor%notfound;
dbms_output.put_line(v_name || ' ' || v_sal || ' ' || v_comm);
END LOOP;
CLOSE emp_cursor;
END;
bulk语句语句可以提交insert、update、delete语句的执行速度。
通过bulk collect减少loop处理的开销。
采用bulk collect可以将查询结果一次性地加载到collections中,而不是通过cursor一条一条地处理。
可以在select into,fetch into,returning into语句使用bulk collect。
注意在使用bulk collect时,所有的into变量都必须是collections。
DECLARE
-- 定义REF游标
TYPE my_cur IS REF CURSOR;
emp_cur my_cur;
-- 定义集合
TYPE namelist IS TABLE OF t_emp.NAME%TYPE;
TYPE sallist IS TABLE OF t_emp.sal%TYPE;
TYPE commlist IS TABLE OF t_emp.comm%TYPE;
names namelist;
sals sallist;
comms commlist;
BEGIN
-- 打开游标,指定数据集
OPEN emp_cur FOR
'select name,sal,comm from t_emp where sal>:1 order by sal desc'
USING 6000;
-- 通过使用bulk直接把集合数据放入声明好的集合中,减少loop的开销
FETCH emp_cur BULK COLLECT INTO names,sals,comms;
CLOSE emp_cur;
dbms_output.put_line('姓名 薪水 奖金');
FOR K IN REVERSE names.FIRST..names.LAST LOOP
dbms_output.put_line(names(K) || ' ' || sals(K) || ' ' || comms(K));
END LOOP;
END;
总结:Cursor与Ref Cursor区别
从技术底层看,两者是相同的。普通plsql cursor在定义时是“静态”的。 而Ref cursors 可以动态打开。
Ref cursor根据逻辑动态打开;而游标cursor定义好了就无法修改了。
ref cursor可以返回给客户端,cursor则不行。
cursor可以是全局的global,ref cursor则必须定义在过程或函数中。
ref cursor可以在子程序间传递,cursor则不行。
cursor中定义的静态sql比ref cursor效率高,所以ref cursor通常用在:向客户端返回结果集。