如何在Oracle PL SQL中的嵌套for循环中使用动态表

时间:2019-02-14 08:54:56

标签: sql plsql oracle11g dynamic-sql

我有一个oracle pl sql脚本,其中有两个for循环(嵌套)。在第二个循环中,我无法在选择查询中动态创建表名。它总是采用静态查询。但是我想要动态表名,例如SIGNALALERTPROP_1,SIGNALALERTPROP_2 ...等。请有人帮忙解决此问题。我给出了以下sql脚本

/**
 * 
 * Script to add two new columns abbrev and color to SIGNALALERTPROP_% table * 

 * 
 * Prompts for input parameter: update_scope
 * Response can be a specific configuration ID, ALL for all configurations
 * 
 * The script logs progress and errors and warnings to the spool file.
 */

SPOOL update_signalalertprop.log
SET SERVEROUTPUT ON
SET VERIFY OFF
ACCEPT update_scope PROMPT "Enter Signal Configuration ID, or ALL [ALL]: " DEFAULT ALL

declare
configId number;
alertprop_tablename varchar2(20);
v_abrev varchar2(1 CHAR);
v_colorId number;
block varchar2(4000);

procedure executeBlock (block varchar2) is    
begin
  begin
    execute immediate block;
    exception when others then
      dbms_output.put_line('');
      dbms_output.put_line('Error executing...');
      dbms_output.put_line(substr(block, 1, 100));
      dbms_output.put_line(SQLERRM); 
      dbms_output.put_line('');
      return;
  end; 
end;

function stringToInt(p_str in varchar2) return number as
 retVal number := null;
begin
 if regexp_instr(p_str, '^[[:space:]]*[[:digit:]]{1,5}[[:space:]]*$') > 0 then
  retVal := to_number(p_str);
 end if;
return retVal;
end;

function does_constraint_exist (i_constraint_name varchar2 ) return boolean is    
    cnt number;    
    begin
    select count(*) into cnt from user_constraints where constraint_name = i_constraint_name;
    return (cnt > 0);
end; 

begin
    configId := stringToInt('&update_scope');
    alertprop_tablename := 'SIGNALALERTPROP_' || configId;
FOR v_rec IN (select 'SIGNALALERTPROP' item_type, id config_id from signalconfig where id = decode(configId, null, id, configId)) LOOP
    dbms_output.put_line('');
    dbms_output.put_line('Adding Columns to SIGNALALERTPROP_' || v_rec.config_id );
    dbms_output.put_line('table_name=' || v_rec.item_type || ', config_id=' || v_rec.config_id);
    dbms_output.put_line('');
    block := 'ALTER TABLE SIGNALALERTPROP_' || v_rec.config_id || ' ADD (ABBREV VARCHAR2(1 CHAR) DEFAULT null, COLOR DEFAULT 0 NOT NULL )';
    executeBlock(block);

    -- adding foreign key
    if(not does_constraint_exist('SIGNALALERTPROP_COLOR_'||configId||'_FK'))
    then
      block := 'ALTER TABLE "SIGNALALERTPROP_'||configId||'" ADD CONSTRAINT "SIGNALALERTPROP_COLOR_'||configId||'_FK" FOREIGN KEY ( color )
      REFERENCES "SIGNALALERTCOLORS" ( id )
      NOT DEFERRABLE';
      executeBlock(block);
    end if; 

    -- update color and abbrev for tracked alerts
    -- 
 FOR v_alert_rec IN (select ID alertPropId, LABEL alertLabel from alertprop_tablename WHERE ALERT_TYPE = 2 ) LOOP
    v_abrev := SUBSTR(v_alert_rec.alertLabel, 1, 1);    
    v_colorId := MOD(v_alert_rec.alertPropId, 14) + 1;
    dbms_output.put_line('v_abrev ' || v_abrev);
    dbms_output.put_line('v_colorId ' || v_colorId);
    block := 'UPDATE SIGNALALERTPROP_'||configId||  ' SET COLOR = ' || v_colorId || ', ABBREV = ' || v_abrev || ' WHERE ID = ' || v_alert_rec.alertPropId ;
    executeBlock(block);    
    dbms_output.put_line('block ' || block);

END LOOP; 
END LOOP;
commit; 
end;
/
spool off;

我遇到类似v_alert_rec无效的错误。我已经检查了FOR v_alert_rec IN(从alertprop_tablename WHERE ALERT_TYPE = 2中选择ID alertPropId,LABEL alertLabel)循环此行,因为alertprop_tablename未填充,因此它失败了。

1 个答案:

答案 0 :(得分:1)

alertprop_tablename不是数据库对象,因此尝试从中选择值将无效。

您需要的是动态SQL的游标,并在其中进行遍历。

Here is an example of how that works