DBMS_UTILITY.EXEC_DDL_STATEMENT
kører kun DDL pålideligt. Hvis du prøver at køre det med en PL/SQL-blok, vil det lydløst fejle og ikke køre noget.
Dette kan demonstreres ved at køre en PL/SQL-blok, der åbenbart skulle mislykkes. Koden nedenfor skal generer ORA-01476: divisor is equal to zero
. Men i stedet gør det ingenting.
begin
[email protected](
q'[declare v_test number; begin v_test := 1/0; end;]'
);
end;
/
Brug en midlertidig procedure til at køre en PL/SQL-blok eksternt. Opret proceduren med DBMS_UTILITY.EXEC_DDL_STATEMENT
og kald det derefter med indbygget dynamisk SQL.
begin
[email protected](
q'[
create or replace procedure test_procedure
is
v_test number;
begin
v_test := 1/0;
end;
]'
);
execute immediate 'begin [email protected]; end;';
end;
/
RESULTS:
ORA-01476: divisor is equal to zero
ORA-06512: at "JHELLER.TEST_PROCEDURE", line 5
ORA-06512: at line 1
ORA-06512: at line 12
Jeg tror, at denne adfærd er en fejl. Oracle burde kaste en fejl i stedet for simpelthen ikke at gøre noget.
Velkommen til sammenkædningshelvede. Strenge bliver rodet, når de er indlejret 4 niveauer dybt. Men der er et par ting, du kan gøre for at gøre livet lettere:
- Brug indlejrede alternative citeringsmekanismer. For eksempel
q'[ ... ]'
, inde i enq'< ... >'
osv. - Brug strenge med flere linjer. Der er ingen grund til at sammenkæde flere linjer, bare brug en enkelt streng.
- Brug ekstra mellemrum til at hjælpe med at identificere starten og slutningen af strenge. Når tingene bliver så vanvittige, er det værd at sætte en streng-afgrænsning på en linje helt af sig selv, så alt er nemt at stille op.
- Brug
REPLACE
i stedet for sammenkædning.
Jeg omformaterede en del af din kode ved hjælp af disse tips. Stackoverflow forstår ikke den alternative citeringsmekanisme, men strengene burde se bedre ud i en god Oracle SQL-editor.
declare
v_db_name varchar2(30) := 'myself';
sql_update varchar2(32767);
begin
execute immediate replace(
q'[
begin
[email protected]#DB_NAME#
(
q'<
create or replace procedure cw_drop_table is
sql_drop varchar2(2000);
begin
sql_drop :=
q'{
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE iSecurity2_dupes_bak';
EXCEPTION WHEN OTHERS THEN
IF SQLCODE != -942 THEN
NULL;
END IF;
END;
}';
execute immediate sql_drop;
end;
>'
);
execute immediate 'begin [email protected]#DB_NAME#; end;';
end;
]', '#DB_NAME#', v_db_name);
sql_update := 'create table iSecurity2_dupes_bak as select * from iSecurity2';
execute immediate 'begin [email protected]'||v_db_name||
'(:sql_update); end;' using sql_update;
commit;
end;
/