12 动态SQL语句和动态PLSQL语句
SQL语句 -- 静态的SQL语句、动态的SQL语句
静态的SQL语句 -- 在编译的时候已经确定的SQL,语法和语义引用也是在编译的时候确定下来的
动态的SQL语句 -- 由字符串组成,在运行的时候编译和执行
12.1 动态SQL语句
(1) 动态SQL的简单案例
案例1: 动态创建表示例
declare
dyn_tab_name varchar2(30):='temp';
dyn_string varchar2(150);
begin
dyn_string:='create table '||dyn_tab_name||' (col number not null)';
execute immediate dyn_string; --动态运行,在匿名块里面调用DDL,要加execute immediate
end;
SQL> desc temp;
Name Type Nullable Default Comments
---- ------ -------- ------- --------
COL NUMBER
改写为存储过程:
create or replace procedure p21 is
dyn_tab_name varchar2(30):='temp';
dyn_string varchar2(150);
begin
dyn_string:='create taeble '||dyn_tab_name||' (col number not null)'; --有语法错误的,但是编译的时候不会报错
execute immediate dyn_string;
end;
SQL> exec p21; --在执行的时候报错
BEGIN p21; END;
*
ERROR at line 1:
ORA-00901: invalid CREATE command
ORA-06512: at "PLSQL.P21", line 6
ORA-06512: at line 1
create or replace procedure p21 is
dyn_tab_name varchar2(30):='temp';
dyn_string varchar2(150);
begin
dyn_string:='create table '||dyn_tab_name||' (col number not null)';
execute immediate dyn_string;
end;
SQL> exec p21;
BEGIN p21; END;
*
ERROR at line 1:
ORA-01031: insufficient privileges --权限不足
ORA-06512: at "PLSQL.P21", line 6
ORA-06512: at line 1
create or replace procedure p21 authid current_user is --正确的写法
--在存储过程中出现动态SQL的时候,需要在SP的头部加上authid current_user显式授权语句,将执行的权限授给当前的用户
dyn_tab_name varchar2(30):='temp1';
dyn_string varchar2(150);
begin
dyn_string:='create table '||dyn_tab_name||' (col number not null)';
execute immediate dyn_string;
end;
SQL> exec p21;
PL/SQL procedure successfully completed.
SQL> desc temp1;
Name Null? Type
----------------------------------------- -------- ----------------------------
COL NOT NULL NUMBER
总结:在存储过程中使用动态SQL语句,如果SQL语句语法有问题,在编译的时候不会报错,只有在调用SP的时候才会报错
在存储过程中出现动态SQL的时候,需要在SP的头部加上authid current_user显式授权语句,将执行的权限授给当前的用户
案例2:动态创建表
create or replace procedure create_dyn_table(i_region_name in varchar2,retcd out number,errmsg out varchar2) authid current_user is
dyn_tab_name varchar2(200);
dyn_string varchar2(2000);
begin
dyn_string:='';
dyn_tab_name:='ORDERS_FOR_'||replace(i_region_name,' ',''); --去掉空格
dyn_string:='create table '||dyn_tab_name||' (order_id number(10) primary key,order_date date not null,total_qty number,total_price number(15,2))';
execute immediate dyn_string;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
测试:
declare
v_sqlcode number;
v_sqlerrm varchar2(100);
begin
create_dyn_table(' u k ',v_sqlcode,v_sqlerrm);
dbms_output.put_line(v_sqlerrm);
end;
select * from orders_for_uk;
案例3:通过动态SQL给表添加外键
create or replace procedure create_dyn_table2(i_region_name in varchar2,retcd out number,errmsg out varchar2) authid current_user is
dyn_tab_name varchar2(200);
dyn_string varchar2(2000);
begin
dyn_tab_name:='ORDERS_ITEMS_FOR_'||replace(i_region_name,' ','');
dyn_string:='create table '||dyn_tab_name||' (order_id number(10) not null,item_id varchar2(20) not null,unit_pirce number(15,2),quantity number)';
execute immediate dyn_string;
dyn_string:='alter table '||dyn_tab_name||' add constraint '||' FK_OIFOR_'||replace(i_region_name,' ','')||' foreign key(order_id) references orders_for_'||replace(i_region_name,' ','')||'(order_id)';
execute immediate dyn_string;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
测试:
declare
v_sqlcode number;
v_sqlerrm varchar2(100);
begin
create_dyn_table2(' u k ',v_sqlcode,v_sqlerrm);
dbms_output.put_line(v_sqlerrm);
end;
select * from orders_items_for_uk;
select * from user_constraints where table_name='ORDERS_ITEMS_FOR_UK';
案例4:按照地区配置表,创建每个销售区域订单表跟订单明细表
地区配置表:
insert into region_tab values(1,'region1');
insert into region_tab values(2,'region2');
insert into region_tab values(3,'region3');
insert into region_tab values(4,'region4');
commit;
select * from region_tab;
region_tab -> orders_for_
-> orders_items_for_
有四个销售区域,每个销售区域需要有订单表跟订单明细表,表的结构都是一样的
create or replace procedure create_dyn_for_all(retcd out number,errmsg out varchar2) authid current_user is
cursor csr_region is select * from region_tab;
begin
for idx in csr_region loop
create_dyn_table(idx.region_name,retcd,errmsg);
if retcd <> 0 then
exit;
end if;
create_dyn_table2(idx.region_name,retcd,errmsg);
if retcd <> 0 then
exit;
end if;
end loop;
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
测试:
declare
v_sqlcode number;
v_sqlerrm varchar2(100);
begin
create_dyn_for_all(v_sqlcode,v_sqlerrm);
dbms_output.put_line(v_sqlerrm);
end;
select * from user_tables where table_name like 'ORDERS%'; --查看到新创建了8个表
(2) 动态创建表
设计方式--根据配置表动态实现功能,只需要维护外面的配置表的内容,将功能封装
需求:字段名和表名都用配置表来配置,实现动态创建表的过程
步骤:
A 创建表1:配置表名
create table table_config(
tab_id number primary key,
table_name varchar2(20) not null,
crt_flag varchar2(2)
);
B 插入初始化数据:
insert into table_config values(1,'A','0');
insert into table_config values(2,'B','0');
commit;
C 创建表2:配置字段的表
create table column_config(
col_id number not null,
tab_id number not null,
col_name varchar2(20),
col_type varchar2(20),
col_length number,
col_pre number
);
添加主外键:
alter table column_config add constraint PK_COL_CFG primary key(col_id,tab_id);
alter table column_config add constraint FK_COL_CFG foreign key(tab_id) references table_config(tab_id);
D 初始化字段表
insert into column_config values(1,1,'A1','varchar2',20,null);
insert into column_config values(2,1,'A2','char',3,null);
insert into column_config values(3,1,'A3','number',12,null);
insert into column_config values(4,1,'A4','number',11,4);
insert into column_config values(5,1,'A5','date',null,null);
insert into column_config values(6,2,'B1','varchar2',22,null);
insert into column_config values(7,2,'B2','char',13,null);
insert into column_config values(8,2,'B3','number',20,null);
insert into column_config values(9,2,'B4','date',null,null);
insert into column_config values(10,2,'B5','number',12,2);
commit;
E 编写功能模块
模块1:读取字段配置表进行字段类型串的拼接
create or replace function dyn_type(i_type in varchar2,i_length in number,i_pre in number) return varchar2 is
v_dyn_type varchar2(1000);
begin
if i_type='varchar2' then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_type='char' then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_type='date' then
v_dyn_type:=i_type;
elsif i_type='number' then
if i_length is not null and i_pre is not null then
v_dyn_type:=i_type||'('||i_length||','||i_pre||')';
elsif i_length is not null and i_pre is null then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_length is null and i_pre is null then
v_dyn_type:=i_type;
end if;
end if;
return v_dyn_type;
exception when others then
return '';
end;
模块2:拼接创建表语句中类型模块
create or replace procedure dyn_crt_tab(i_tab_name in varchar2,i_crt_string out varchar2,retcd out number,errmsg out varchar2) authid current_user is
cursor csr_tab is select h.tab_id,h.table_name,o.col_type,o.col_name,o.col_length,o.col_pre
from column_config o,table_config h
where o.tab_id=h.tab_id
and h.table_name=i_tab_name;
csr_rec csr_tab%rowtype;
dyn_col_type varchar2(100);
dyn_tab_p varchar2(4000);
begin
open csr_tab;
dyn_tab_p:='';
loop
fetch csr_tab into csr_rec;
exit when (csr_tab%notfound);
dyn_col_type:=dyn_type(csr_rec.col_type,csr_rec.col_length,csr_rec.col_pre)||','; --调用拼接字段的函数
dyn_tab_p:=dyn_tab_p||csr_rec.col_name||' '||dyn_col_type;
end loop;
dyn_tab_p:=substr(dyn_tab_p,1,instr(dyn_tab_p,',',-1,1)-1); --将最后一个','去掉
i_crt_string:=dyn_tab_p;
close csr_tab;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
模块3:执行模块
create or replace procedure dyn_crt(retcd out number,errmsg out varchar2) authid current_user is
cursor csr_tab is select h.tab_id,h.table_name
from table_config h
where h.crt_flag='0';
csr_rec csr_tab%rowtype;
dyn_string varchar2(4000);
v_crt_table varchar2(4000);
v_sqlcode number;
v_sqlerrm varchar2(200);
begin
open csr_tab;
dyn_string:='';
loop
fetch csr_tab into csr_rec;
exit when(csr_tab%notfound);
dyn_crt_tab(csr_rec.table_name,v_crt_table,v_sqlcode,v_sqlerrm); --调用表拼接的存储过程
dyn_string:='create table '||csr_rec.table_name||'('||v_crt_table||')';
execute immediate dyn_string;
update table_config set crt_flag='1' where tab_id=csr_rec.tab_id;
commit;
end loop;
close csr_tab;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
测试:
declare
v_sqlcode number;
v_sqlerrm varchar2(200);
begin
dyn_crt(v_sqlcode,v_sqlerrm);
dbms_output.put_line(v_sqlerrm);
end;
SQL> desc a
Name Null? Type
----------------------------------------- -------- ----------------------------
A1 VARCHAR2(20)
A2 CHAR(3)
A3 NUMBER(12)
A4 NUMBER(11,4)
A5 DATE
SQL> desc b
Name Null? Type
----------------------------------------- -------- ----------------------------
B1 VARCHAR2(22)
B2 CHAR(13)
B3 NUMBER(20)
B4 DATE
B5 NUMBER(12,2)
练习:
A 将上面3个子程序封装在一个package中存储,其中函数还有另外一个存储作为私有对象。
在包头加上authid current_user
存储过程中authid current_user去掉
B 开发一个动态drop表的SP封装在上面创建的包中,要求,在table_config表上添加一个字段,drop_flag varchar2(2)
删除标记,如果为1,表示要删除,如果为0表示保留,将所有标记为1的表删除掉,如果删除的时候发现已经被删除了,则要捕获异常将数据插入到我们之前创建异常监控表中,与此同时创建标记crt_flag置为0
alter table table_config add drop_flag varchar2(2);
C 开发动态删除和添加字段的模块,需要在字段配置表上添加删除和添加的标记字段。
alter table column_config add add_flag varchar2(2);
alter table column_config add del_flag varchar2(2);
包头:
create or replace package dyn_pkg authid current_user is
procedure dyn_crt(retcd out number,errmsg out varchar2);
procedure dyn_drop(retcd out number, errmsg out varchar2);
procedure dyn_add(retcd out number, errmsg out varchar2);
procedure dyn_del(retcd out number, errmsg out varchar2);
end dyn_pkg;
包体:
create or replace package body dyn_pkg is
function dyn_type(i_type in varchar2,i_length in number,i_pre in number)
return varchar2 is
v_dyn_type varchar2(1000);
begin
if i_type='VARCHAR2' then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_type='CHAR' then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_type='DATE' then
v_dyn_type:=i_type;
elsif i_type='NUMBER' then
if i_length is not null and i_pre is not null then
v_dyn_type:=i_type||'('||i_length||','||i_pre||')';
elsif i_length is not null and i_pre is null then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_length is null and i_pre is null then
v_dyn_type:=i_type;
end if;
end if;
return v_dyn_type;
exception when others then
return '';
end;
procedure dyn_crt_tab(i_tab_name in varchar2,i_crt_string out varchar2,retcd out number,errmsg out varchar2) is
cursor csr_tab is select h.tab_id,h.table_name,o.col_type,o.col_name,o.col_length,o.col_pre
from column_config o,table_config h
where o.tab_id=h.tab_id
and h.table_name=i_tab_name;
csr_rec csr_tab%rowtype;
dyn_col_type varchar2(100);
dyn_tab_p varchar2(4000);
begin
open csr_tab;
dyn_tab_p:='';
loop
fetch csr_tab into csr_rec;
exit when(csr_tab%notfound);
dyn_col_type:=dyn_type(csr_rec.col_type,csr_rec.col_length,csr_rec.col_pre)||','; --调用拼接字段的函数
dyn_tab_p:=dyn_tab_p||csr_rec.col_name||' '||dyn_col_type;
end loop;
dyn_tab_p:=substr(dyn_tab_p,1,instr(dyn_tab_p,',',-1,1)-1); --将最后一个‘,’去掉
i_crt_string:=dyn_tab_p;
close csr_tab;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
procedure dyn_crt(retcd out number,errmsg out varchar2) is
cursor csr_tab is select h.tab_id,h.table_name
from table_config h
where h.crt_flag='0';
csr_rec csr_tab%rowtype;
dyn_string varchar2(4000);
v_crt_table varchar2(4000);
v_retcd number;
v_errmsg varchar2(150);
begin
open csr_tab;
dyn_string:='';
loop
fetch csr_tab into csr_rec;
exit when(csr_tab%notfound);
dyn_crt_tab(csr_rec.table_name,v_crt_table,v_retcd,v_errmsg); --调用表拼接的函数
dyn_string:='create table '||csr_rec.table_name||'('||v_crt_table||')';
execute immediate dyn_string;
update table_config set crt_flag='1' where tab_id=csr_rec.tab_id;
commit;
end loop;
close csr_tab;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
procedure dyn_drop(retcd out number, errmsg out varchar2) is
cursor csr_drop is
select table_name, tab_id
from table_config
where drop_flag = '1';
csr_rec csr_drop%rowtype;
dyn_drop_config varchar2(100);
sqlnotfound exception;
pragma exception_init(sqlnotfound,-942);
v_sqlcode number;
v_sqlerrm varchar2(100);
begin
open csr_drop;
dyn_drop_config := '';
loop
fetch csr_drop
into csr_rec;
exit when(csr_drop%notfound);
dyn_drop_config := 'drop table ' || csr_rec.table_name;
execute immediate dyn_drop_config;
end loop;
close csr_drop;
retcd := 0;
errmsg := 'successful';
exception
when sqlnotfound then
v_sqlcode:=sqlcode;
v_sqlerrm:=sqlerrm;
insert into exception_monitor values
(csr_rec.table_name,
csr_rec.tab_id,
upper('dyn_drop'),
upper('sqlnotfound'),
v_sqlcode,
v_sqlerrm,
sysdate);
update table_config
set drop_flag = '0'
where tab_id = csr_rec.tab_id;
when others then
retcd := sqlcode;
errmsg := sqlerrm;
end;
procedure dyn_add(retcd out number, errmsg out varchar2) is
cursor csr_add is
select t.table_name,
t.tab_id,
c.col_id,
c.col_name,
c.col_type,
c.col_length,
c.col_pre
包头:
create or replace package dyn_pkg authid current_user is
procedure dyn_crt(retcd out number,errmsg out varchar2);
procedure dyn_drop(retcd out number, errmsg out varchar2);
procedure dyn_add(retcd out number, errmsg out varchar2);
procedure dyn_del(retcd out number, errmsg out varchar2);
end dyn_pkg;
包体:
create or replace package body dyn_pkg is
function dyn_type(i_type in varchar2,i_length in number,i_pre in number)
return varchar2 is
v_dyn_type varchar2(1000);
begin
if i_type='VARCHAR2' then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_type='CHAR' then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_type='DATE' then
v_dyn_type:=i_type;
elsif i_type='NUMBER' then
if i_length is not null and i_pre is not null then
v_dyn_type:=i_type||'('||i_length||','||i_pre||')';
elsif i_length is not null and i_pre is null then
v_dyn_type:=i_type||'('||i_length||')';
elsif i_length is null and i_pre is null then
v_dyn_type:=i_type;
end if;
end if;
return v_dyn_type;
exception when others then
return '';
end;
procedure dyn_crt_tab(i_tab_name in varchar2,i_crt_string out varchar2,retcd out number,errmsg out varchar2) is
cursor csr_tab is select h.tab_id,h.table_name,o.col_type,o.col_name,o.col_length,o.col_pre
from column_config o,table_config h
where o.tab_id=h.tab_id
and h.table_name=i_tab_name;
csr_rec csr_tab%rowtype;
dyn_col_type varchar2(100);
dyn_tab_p varchar2(4000);
begin
open csr_tab;
dyn_tab_p:='';
loop
fetch csr_tab into csr_rec;
exit when(csr_tab%notfound);
dyn_col_type:=dyn_type(csr_rec.col_type,csr_rec.col_length,csr_rec.col_pre)||','; --调用拼接字段的函数
dyn_tab_p:=dyn_tab_p||csr_rec.col_name||' '||dyn_col_type;
end loop;
dyn_tab_p:=substr(dyn_tab_p,1,instr(dyn_tab_p,',',-1,1)-1); --将最后一个‘,’去掉
i_crt_string:=dyn_tab_p;
close csr_tab;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
procedure dyn_crt(retcd out number,errmsg out varchar2) is
cursor csr_tab is select h.tab_id,h.table_name
from table_config h
where h.crt_flag='0';
csr_rec csr_tab%rowtype;
dyn_string varchar2(4000);
v_crt_table varchar2(4000);
v_retcd number;
v_errmsg varchar2(150);
begin
open csr_tab;
dyn_string:='';
loop
fetch csr_tab into csr_rec;
exit when(csr_tab%notfound);
dyn_crt_tab(csr_rec.table_name,v_crt_table,v_retcd,v_errmsg); --调用表拼接的函数
dyn_string:='create table '||csr_rec.table_name||'('||v_crt_table||')';
execute immediate dyn_string;
update table_config set crt_flag='1' where tab_id=csr_rec.tab_id;
commit;
end loop;
close csr_tab;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
procedure dyn_drop(retcd out number, errmsg out varchar2) is
cursor csr_drop is
select table_name, tab_id
from table_config
where drop_flag = '1';
csr_rec csr_drop%rowtype;
dyn_drop_config varchar2(100);
sqlnotfound exception;
pragma exception_init(sqlnotfound,-942);
v_sqlcode number;
v_sqlerrm varchar2(100);
begin
open csr_drop;
dyn_drop_config := '';
loop
fetch csr_drop
into csr_rec;
exit when(csr_drop%notfound);
dyn_drop_config := 'drop table ' || csr_rec.table_name;
execute immediate dyn_drop_config;
end loop;
close csr_drop;
retcd := 0;
errmsg := 'successful';
exception
when sqlnotfound then
v_sqlcode:=sqlcode;
v_sqlerrm:=sqlerrm;
insert into exception_monitor values
(csr_rec.table_name,
csr_rec.tab_id,
upper('dyn_drop'),
upper('sqlnotfound'),
v_sqlcode,
v_sqlerrm,
sysdate);
update table_config
set drop_flag = '0'
where tab_id = csr_rec.tab_id;
when others then
retcd := sqlcode;
errmsg := sqlerrm;
end;
procedure dyn_add(retcd out number, errmsg out varchar2) is
cursor csr_add is
select t.table_name,
t.tab_id,
c.col_id,
c.col_name,
c.col_type,
c.col_length,
c.col_pre
from table_config t, column_config c
where t.tab_id = c.tab_id
and c.add_flag = '1';
csr_rec csr_add%rowtype;
dyn_col_type varchar2(200);
dyn_add_string varchar2(4000);
begin
open csr_add;
dyn_add_string := '';
loop
fetch csr_add
into csr_rec;
exit when(csr_add%notfound);
dyn_col_type := dyn_type(csr_rec.col_type,
csr_rec.col_length,
csr_rec.col_pre);
dyn_add_string := 'alter table ' || csr_rec.table_name ||
' add ' || csr_rec.col_name || ' ' ||
dyn_col_type;
execute immediate dyn_add_string;
update column_config set add_flag='0' where tab_id=csr_rec.tab_id and col_id=csr_rec.col_id;
end loop;
close csr_add;
retcd := 0;
errmsg := 'successful!';
exception
when others then
retcd := sqlcode;
errmsg := sqlerrm;
end;
procedure dyn_del(retcd out number, errmsg out varchar2) is
cursor csr_del is
select t.table_name, c.col_name ,t.tab_id , c.col_id
from table_config t, column_config c
where t.tab_id = c.tab_id
and c.del_flag = '1';
dyn_del_string varchar2(4000);
csr_rec csr_del%rowtype;
begin
open csr_del;
dyn_del_string := '';
loop
fetch csr_del
into csr_rec;
exit when(csr_del%notfound);
dyn_del_string := 'alter table ' || csr_rec.table_name ||
' drop column ' || csr_rec.col_name;
execute immediate dyn_del_string;
update column_config set del_flag='0' where tab_id=csr_rec.tab_id and col_id=csr_rec.col_id;
end loop;
close csr_del;
retcd := 0;
errmsg := 'successful!';
exception
when others then
retcd := sqlcode;
errmsg := sqlerrm;
end;
end dyn_pkg;
from table_config t, column_config c
where t.tab_id = c.tab_id
and c.add_flag = '1';
csr_rec csr_add%rowtype;
dyn_col_type varchar2(200);
dyn_add_string varchar2(4000);
begin
open csr_add;
dyn_add_string := '';
loop
fetch csr_add
into csr_rec;
exit when(csr_add%notfound);
dyn_col_type := dyn_type(csr_rec.col_type,
csr_rec.col_length,
csr_rec.col_pre);
dyn_add_string := 'alter table ' || csr_rec.table_name ||
' add ' || csr_rec.col_name || ' ' ||
dyn_col_type;
execute immediate dyn_add_string;
update column_config set add_flag='0' where tab_id=csr_rec.tab_id and col_id=csr_rec.col_id;
end loop;
close csr_add;
retcd := 0;
errmsg := 'successful!';
exception
when others then
retcd := sqlcode;
errmsg := sqlerrm;
end;
procedure dyn_del(retcd out number, errmsg out varchar2) is
cursor csr_del is
select t.table_name, c.col_name ,t.tab_id , c.col_id
from table_config t, column_config c
where t.tab_id = c.tab_id
and c.del_flag = '1';
dyn_del_string varchar2(4000);
csr_rec csr_del%rowtype;
begin
open csr_del;
dyn_del_string := '';
loop
fetch csr_del
into csr_rec;
exit when(csr_del%notfound);
dyn_del_string := 'alter table ' || csr_rec.table_name ||
' drop column ' || csr_rec.col_name;
execute immediate dyn_del_string;
update column_config set del_flag='0' where tab_id=csr_rec.tab_id and col_id=csr_rec.col_id;
end loop;
close csr_del;
retcd := 0;
errmsg := 'successful!';
exception
when others then
retcd := sqlcode;
errmsg := sqlerrm;
end;
end dyn_pkg;
###########################################################################################
12.2 动态PLSQL语句
(1) 动态单行select语句
A 录入订单表和订单明细表的初始化数据
insert into orders_for_region1 values(1,sysdate,null,null);
insert into orders_items_for_region1 values(1,'A001',20,13);
insert into orders_items_for_region1 values(1,'A001',23,10);
insert into orders_items_for_region1 values(1,'A001',11,5);
commit;
B 创建SP,更新订单表的值
create or replace procedure update_dyn_table(i_region_name in varchar2,i_order_id in number,retcd out number,errmsg out varchar2) authid current_user is
dyn_upd_string varchar2(2000);
dyn_query_string varchar2(1000);
dyn_tab_name1 varchar2(30);
dyn_tab_name2 varchar2(30);
v_total_price number;
v_total_quantity number;
begin
dyn_tab_name1:='ORDERS_FOR_'||replace(i_region_name,' ','');
dyn_tab_name2:='ORDERS_ITEMS_FOR_'||replace(i_region_name,' ','');
dyn_query_string:='select sum(quantity),sum(quantity*unit_pirce) from '||dyn_tab_name2||' where order_id=:input_order_id'; --:input_order_id表示绑定变量
execute immediate dyn_query_string into v_total_quantity,v_total_price using i_order_id;
dyn_upd_string:='update '||dyn_tab_name1||' set total_qty=:v_total_qty,total_price=:v_total_price where order_id=:input_order_id';
execute immediate dyn_upd_string using v_total_quantity,v_total_price,i_order_id;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
测试:
declare
v_sqlcode number;
v_sqlerrm varchar2(200);
begin
update_dyn_table('region1',1,v_sqlcode,v_sqlerrm);
dbms_output.put_line(v_sqlerrm);
end;
查询:
select * from orders_for_region1;
注意:
A 动态PLSQL语句中,select语句需要用into来接收参数值
B 绑定变量在动态PLSQL中,用冒号前置的方式来定义,不需要声明
C 执行的时候,绑定变量需要用using关键字来赋值
(2) 动态多行的select语句
A 初始化数据
insert into orders_for_region1 values(2,sysdate,null,null);
insert into orders_items_for_region1 values(2,'A001',30,13);
insert into orders_items_for_region1 values(2,'A001',33,10);
insert into orders_items_for_region1 values(2,'A001',11,7);
insert into orders_for_region1 values(3,sysdate,null,null);
insert into orders_items_for_region1 values(3,'A001',50,13);
insert into orders_items_for_region1 values(3,'A001',63,7);
insert into orders_items_for_region1 values(3,'A001',21,5);
insert into orders_for_region1 values(4,sysdate,null,null);
insert into orders_items_for_region1 values(4,'A001',30,13);
insert into orders_items_for_region1 values(4,'A001',35,10);
insert into orders_items_for_region1 values(4,'A001',12,5);
commit;
B 编写SP实现多行的更新
create or replace procedure update_dyn_all_table(i_region_name in varchar2,retcd out number,errmsg out varchar2) authid current_user is
dyn_upd_string varchar2(1000);
dyn_query_string varchar2(1000);
dyn_tab_name varchar2(30);
v_total_price number;
v_total_quantity number;
type csr_dyn is ref cursor;
csr_dyn1 csr_dyn;
v_order_id number;
begin
dyn_tab_name:='ORDERS_ITEMS_FOR_'||replace(i_region_name,' ','');
dyn_query_string:='select distinct order_id from '||dyn_tab_name;
open csr_dyn1 for dyn_query_string; --动态的方式打开游标
loop
fetch csr_dyn1 into v_order_id;
exit when(csr_dyn1%notfound);
update_dyn_table(i_region_name,v_order_id,retcd,errmsg);
if retcd <> 0 then
exit;
end if;
end loop;
close csr_dyn1;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
测试:
declare
v_sqlcode number;
v_sqlerrm varchar2(200);
begin
update_dyn_all_table('region1',v_sqlcode,v_sqlerrm);
dbms_output.put_line(v_sqlerrm);
end;
验证:
select * from orders_for_region1;
目前为止只是处理了一个销售区域,总共有四个销售区域,怎样处理四个销售区域用一个SP
A 初始化
insert into orders_for_region1 values(1,sysdate,null,null);
insert into orders_items_for_region1 values(1,'A001',30,13);
insert into orders_items_for_region1 values(1,'A001',33,10);
insert into orders_items_for_region1 values(1,'A001',11,7);
insert into orders_for_region1 values(2,sysdate,null,null);
insert into orders_items_for_region1 values(2,'A001',30,13);
insert into orders_items_for_region1 values(2,'A001',33,10);
insert into orders_items_for_region1 values(2,'A001',11,7);
insert into orders_for_region1 values(3,sysdate,null,null);
insert into orders_items_for_region1 values(3,'A001',50,13);
insert into orders_items_for_region1 values(3,'A001',63,7);
insert into orders_items_for_region1 values(3,'A001',21,5);
insert into orders_for_region1 values(4,sysdate,null,null);
insert into orders_items_for_region1 values(4,'A001',30,13);
insert into orders_items_for_region1 values(4,'A001',35,10);
insert into orders_items_for_region1 values(4,'A001',12,5);
commit;
insert into orders_for_region2 values(1,sysdate,null,null);
insert into orders_items_for_region2 values(1,'A001',30,13);
insert into orders_items_for_region2 values(1,'A001',33,10);
insert into orders_items_for_region2 values(1,'A001',11,7);
insert into orders_for_region2 values(2,sysdate,null,null);
insert into orders_items_for_region2 values(2,'A001',30,13);
insert into orders_items_for_region2 values(2,'A001',33,10);
insert into orders_items_for_region2 values(2,'A001',11,7);
insert into orders_for_region2 values(3,sysdate,null,null);
insert into orders_items_for_region2 values(3,'A001',50,13);
insert into orders_items_for_region2 values(3,'A001',63,7);
insert into orders_items_for_region2 values(3,'A001',21,5);
insert into orders_for_region2 values(4,sysdate,null,null);
insert into orders_items_for_region2 values(4,'A001',30,13);
insert into orders_items_for_region2 values(4,'A001',35,10);
insert into orders_items_for_region2 values(4,'A001',12,5);
commit;
insert into orders_for_region3 values(1,sysdate,null,null);
insert into orders_items_for_region3 values(1,'A001',30,13);
insert into orders_items_for_region3 values(1,'A001',33,10);
insert into orders_items_for_region3 values(1,'A001',11,7);
insert into orders_for_region3 values(2,sysdate,null,null);
insert into orders_items_for_region3 values(2,'A001',30,13);
insert into orders_items_for_region3 values(2,'A001',33,10);
insert into orders_items_for_region3 values(2,'A001',11,7);
insert into orders_for_region3 values(3,sysdate,null,null);
insert into orders_items_for_region3 values(3,'A001',50,13);
insert into orders_items_for_region3 values(3,'A001',63,7);
insert into orders_items_for_region3 values(3,'A001',21,5);
insert into orders_for_region3 values(4,sysdate,null,null);
insert into orders_items_for_region3 values(4,'A001',30,13);
insert into orders_items_for_region3 values(4,'A001',35,10);
insert into orders_items_for_region3 values(4,'A001',12,5);
commit;
insert into orders_for_region4 values(1,sysdate,null,null);
insert into orders_items_for_region4 values(1,'A001',30,13);
insert into orders_items_for_region4 values(1,'A001',33,10);
insert into orders_items_for_region4 values(1,'A001',11,7);
insert into orders_for_region4 values(2,sysdate,null,null);
insert into orders_items_for_region4 values(2,'A001',30,13);
insert into orders_items_for_region4 values(2,'A001',33,10);
insert into orders_items_for_region4 values(2,'A001',11,7);
insert into orders_for_region4 values(3,sysdate,null,null);
insert into orders_items_for_region4 values(3,'A001',50,13);
insert into orders_items_for_region4 values(3,'A001',63,7);
insert into orders_items_for_region4 values(3,'A001',21,5);
insert into orders_for_region4 values(4,sysdate,null,null);
insert into orders_items_for_region4 values(4,'A001',30,13);
insert into orders_items_for_region4 values(4,'A001',35,10);
insert into orders_items_for_region4 values(4,'A001',12,5);
commit;
B 创建SP实现多个区域的销售数据的计算。region_tab
create or replace procedure update_dyn_global(retcd out number,errmsg out varchar2) authid current_user is
cursor csr_region is select region_name from region_tab;
begin
for idx in csr_region loop
update_dyn_all_table(idx.region_name,retcd,errmsg);
if retcd <> 0 then
exit;
end if;
end loop;
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
测试:
declare
v_sqlcode number;
v_sqlerrm varchar2(200);
begin
update_dyn_global(v_sqlcode,v_sqlerrm);
dbms_output.put_line(v_sqlerrm);
end;
验证:
select * from orders_for_region1;
select * from orders_for_region2;
select * from orders_for_region3;
select * from orders_for_region4;
在存储过程中使用动态PLSQL调用存储过程,封装在SP中
create or replace procedure update_dyn_global2(retcd out number,errmsg out varchar2) authid current_user is
begin
execute immediate 'begin update_dyn_global(:1,:2);end;' using out retcd,out errmsg;
--动态PLSQL语句中调用存储过程
retcd:=0;
errmsg:='successful!';
exception when others then
retcd:=sqlcode;
errmsg:=sqlerrm;
end;
练习:
将上面的三个SP封装在一个package中,全部做成公有对象
SCOTT用户下
A 创建一个表emp_salary_grd : 三个列:员工号 empno 、工资等级 sal_level、年薪 sal_anl (sal*12+comm)
B 创建一个SP,用动态PLSQL的方式将这个表的数据装载
C 用动态PSLQL方式调用上面创建的SP
设计一个SP,将PLSQL用户下所有的触发器禁用掉,用动态SQL方式
###########################################################################################