设为首页 收藏本站
查看: 764|回复: 0

[经验分享] plsql动态的sql

[复制链接]

尚未签到

发表于 2018-10-23 09:43:54 | 显示全部楼层 |阅读模式
  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>  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

  >  C 开发动态删除和添加字段的模块,需要在字段配置表上添加删除和添加的标记字段。

  >
  >  包头:
  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>  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方式
  ###########################################################################################


运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-625280-1-1.html 上篇帖子: SQL行列互换很方便 下篇帖子: SQL state [HY000]; error code [3]; 问题分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表