How to use this execute immediate create table to insert values in table - oracle

I am using execute immediate to create table and use this table into my code to insert some values when i run this code .it gives me error that table and view does not exist.why?. this code has ability to create table because when i use drop and create table command with existing table by using execute immediate then my code works fine and when i just remove drop table syntax, my code does not work, Please help me to clear my concept about dynamic SQL-----------
SET serveroutput ON
DECLARE
ddl_table VARCHAR2(200);
r_emp SYS.ODCINUMBERLIST := SYS.ODCINUMBERLIST();
v_array SYS.ODCIVARCHAR2LIST := SYS.ODCIVARCHAR2LIST('ACCT_ID',
'PARENT_ACCT_ID',
'CUST_ID',
'ACCT_NAME',
'BILLING_CYCLE_TYPE',
'PAID_FLAG',
'BILL_DELIVER_METHOD');
BEGIN
ddl_table := 'CREATE TABLE test123(
v_column VARCHAR2(50),
v_count NUMBER
)';
EXECUTE IMMEDIATE ddl_table;
DBMS_OUTPUT.ENABLE;
FOR i IN 1 .. v_array.COUNT LOOP
r_emp.EXTEND;
EXECUTE IMMEDIATE 'SELECT COUNT(*)
FROM account_profile
WHERE NOT REGEXP_LIKE(' ||v_array(i) || ',''[A-Za-z0-9.]'')'
INTO r_emp(i);
IF r_emp(i) <> 0 THEN
DBMS_OUTPUT.PUT_LINE(v_array(i) || ': ' || r_emp(i));
INSERT INTO test123 VALUES (v_array(i), r_emp(i));
END IF;
END LOOP;
END;
/
Error report -
ORA-06550: line 24, column 17:
PL/SQL: ORA-00942: table or view does not exist

Your problem is that the annonymous block is pre-validated (pre-compiled) before it is valid. Oracle will check all objects in use before executing it. Since you are creating test123 dynamically it doesn't exist so your insert statement fails.
You can instead, use an EXECUTE IMMEDIATE command to also insert the data on your test123 table.
The way you use the EXECUTE IMMEDIATE for an insert command is either concatenating the parameters or preparing them, I prefer the later. Like this
execute immediate 'insert into test123 values (:param1,:param2)' using v_array(i), r_emp(i);
Here is the official documentation for the EXECUTE IMMEDIATE command.
Though it shows how it works and explain the usage of it, it doesn't particularly answer you direct question on the comments.
So
can you explain :param1,:param2
Those are called "binding" parameters that will be replaced by the variables used after the using statement. It doesn't matter their name only the order in which they appear on the string. The number of parameters within the dynamic string needs to match the number of parameters after the using statement.
why we use it with : colon and what are these
The colon : there is just to make it easier for the parser to know what to replace and where when using the variables you provided after the using statement
Translating that execute immediate it would be something like this:
... values (:param1,:param2)' using v_array(i), r_emp(i)
Hey "execute immediate" whenever you see :param1 please replace it with the content of the variable I'm providing as v_array(i) and whenever you see :param2 please replace it with the content of the variable I'm providing as r_emp(i)

Related

Getting table data with execute immediate in a loop

I am trying to extract data from tables. The names of multiple tables can be given as comma separated values (like a,b,c) and based on that I need to extract the data into a file. Here is the code, which is run through SQL*Plus:
declare
p_schema_name varchar2(1000) := '&1';
p_table_names varchar2(4000) := '&2';
p_statement varchar2(4000);
begin
p_statement := 'select * from :x'||'.'||':y';
for foo in (
select
regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) as txt
from dual
connect by
regexp_substr (replace(p_table_names, ' ', ''), '[^,]+', 1, level) is not null)
loop
execute immediate p_statement using p_schema_name, foo.txt;
end loop;
end;
When I execute this script then I get the following error:
ORA-00903: invalid table name
ORA-06512: at line 14
Where I am doing wrong?
You can only bind variables, not object names. The bind substitution is done when your query is executed, not when it is parsed. The object names have to be known at parse time.
You have to concatenate the schema and table name into the query:
...
begin
p_statement := 'select * from ';
...
execute immediate p_statement || p_schema_name ||'.'|| foo.txt;
end loop;
end;
Of course that now has the potential for SQL injection, so you need to sanitise the inputs. You can check if they are valid names, or check the extracted tables exist in the specified schema before trying to execute the query. You might find the DBMS_ASSERT package useful.
Although your query won't actually be executed at the moment; from the documentation:
If dynamic_sql_statement is a SELECT statement, and you omit both into_clause and bulk_collect_into_clause, then execute_immediate_statement never executes.
You need to select your data into something, which is going to be tricky if the tables that can be passed in have different structures. If you plan to write the queried data into a file and don't know the structure then you need to use the DBMS_SQL package rather then execute immediate.
Table names and Column names cannot be passed as Bind variables to an Execute immediate statement!
Instead use them as variables and concatenate them.
But then the other error would be that you are missing an INTO clause for the Execute immediate statement processing a SELECT statement as said by the other contributor.
Thanks,
B
As per your question how you are going to handle the output of SELECT * query from PLSQL. I guess you either need to have a ref cursor to anyway use this. Also as per your code if you loop through multiple tables the output will be always overwritten by the next one so you will get the last query output only.
So for this spool the output in a file and iterate to next table.
Hope this info helps.

PL/SQL UPDATE/INSERT with table's variable

It is possible to build a statement using variables for the table name without creating a VARCHAR and using EXECUTE IMMEDIATE?
ex:
#table_name := test_table
UPDATE #table_name
SET col1 = val1
WHERE condition...;
this is my actual workaround:
DECLARE
sql_stmt VARCHAR2(1000);
table_name VARCHAR2(30) := 'test_table';
BEGIN
sql_stmt := 'UPDATE ' || table_name || ' SET col1 = val1...';
EXECUTE IMMEDIATE sql_stmt;
END;
/
"[Is it] possible to build a statement using variables for the table
name without creating a VARCHAR and using EXECUTE IMMEDIATE?"
No.
SQL is a strongly typed language. The compiler requires the actual table name in order to validate the various components of the SQL statement ( projection, filters, etc).
Dynamic SQL (EXECUTE IMMEDIATE and DBMS_SQL) is necessary to short-circuit the compile time validation. Essentially it's a mechanism relieving the compiler of the burden of verifying the SQL and taking it on ourselves (because humans are so much better at such jobs than machines. Not).
Alternatively, it's a mechanism for generating runtime errors instead of compilation errors.
Either way, it's pretty odd to know the name of the COLUMN in the filter but not the name of the TABLE being updated.

Testing native dynamic SQL in Oracle before execution

I have implemented a certain feature in my application where the user can compose queries dynamically from the user interface by pushing around buttons and inserting some values here and there.
The user will not see the generated SQL statement at all.
I was wondering if there is a way to perhaps check the syntax and grammar (e.g. he opened a parantheses '(' and forgot to close it ) of the dynamically generated SQL to ensure that no run-time compilation errors would happen before actually executing the statement using EXECUTE IMMEDIATE.
You could use the dbms_sql.parse procedure to parse the SQL statement assuming the statement is DML not DDL. It would be rather unusual to parse a dynamic SQL statement using the dbms_sql package and then use EXECUTE IMMEDIATE to execute it rather than using dbms_sql.execute but nothing prevents you from mixing dbms_sql and execute immediate.
The code to just parse the SQL statement would be something like
DECLARE
l_cursor integer;
l_sql_stmt varchar2(1000) := <<some SQL statement>>;
BEGIN
l_cursor := dbms_sql.open_cursor;
dbms_sql.parse( l_cursor, l_sql_stmt, dbms_sql.native );
dbms_sql.close_cursor( l_cursor );
END;
You can also use explain plan, this is basically doing the first step of the execution.
SQL> explain plan for select * from dual;
Explained.
SQL is valid, you can also use the explain tables to get the tables, views etc, maybe even estimated run time ...
SQL> explain plan for select * from duall;
explain plan for select * from duall
*
ERROR at line 1:
ORA-00942: table or view does not exist
SQL is invalid, this is why ...
you can also use it in a dynamic statement
SQL> begin execute immediate 'explain plan for ' || ' select * from dual'; end;
2 /
PL/SQL procedure successfully completed.
As always use error-handling, e.g. write a little error log creater package or procedure what u call when it's needed.
DECLARE
my_stmt VARCHAR2(4000):='this will contain my statements';
BEGIN
'begin' || my_stmt || 'end';
EXCEPTION
WHEN OTHERS THEN
prc_my_error_log_creator();
END;
in the log_creator use for example the DBMS_UTILITY.FORMAT_ERROR_BACKTRACE() func to get the stack's contain.
Regards

I Need to Insert a multiple tables data into single table using below code i tried but i have error

If i type my source tables name, data are copy into our target table:
'Create or Replace procedure p
(source_tab varchar2,target_tab varchar2)
As
query varchar2(200);
Type I_tab is table of varchar2(100000) index by binary_integer;
Rec_i I_tab;
Begin
query=’select * from’||source_tab;
Execute immediate query bulk collect into rec_i;
Forall i in rec_i.first..rec_i.last
Execute immediate’insert into’||target_tab||’values’||rec_i(i);
Commit;
End;
/
In the absence of anything useful like the actual compilation or runtime errors are we can do is guess.
As it happens your code has several obvious bloomers.
You appear to be using MS Word type smart quotes ’ whereas Oracle expects regular ASCII dumb quotes '. So that would be a compilation error.
The maximum size of a VARCHAR2 is 32767 so your nested table statement will hurl a compilation error.
You need to put spaces around the key words in the dynamic SQL. Otherwise you'll get a runtime error. So ’insert into’||target_tab||’values’ needs to 'insert into '||target_tab||' values ' . Make sure you check all the strings.
In PL/SQL the assignment operator is :=; = is the test for equality.
Less obvious, but we can't use EXECUTE IMMEDIATE in a FORALL. It's not a programmatic loop, and it needs to be a DML (SQL) statement: EXECUTE IMEMDIATE is PL/SQL. However you can do the same thing with
execute immediate
'insert into '|| target_tab ||
' select * from '|| source_tab

DDL statements in PL/SQL?

I am trying the code below to create a table in PL/SQL:
DECLARE
V_NAME VARCHAR2(20);
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE TEMP(NAME VARCHAR(20))';
EXECUTE IMMEDIATE 'INSERT INTO TEMP VALUES(''XYZ'')';
SELECT NAME INTO V_NAME FROM TEMP;
END;
/
The SELECT statement fails with this error:
PL/SQL: ORA-00942: table or view does not exist
Is it possible to CREATE, INSERT and SELECT all in a single PL/SQL Block one after other?
I assume you're doing something like the following:
declare
v_temp varchar2(20);
begin
execute immediate 'create table temp(name varchar(20))';
execute immediate 'insert into temp values(''XYZ'')';
select name into v_name from temp;
end;
At compile time the table, TEMP, does not exist. It hasn't been created yet. As it doesn't exist you can't select from it; you therefore also have to do the SELECT dynamically. There isn't actually any need to do a SELECT in this particular situation though you can use the returning into syntax.
declare
v_temp varchar2(20)
begin
execute immediate 'create table temp(name varchar2(20))';
execute immediate 'insert into temp
values(''XYZ'')
returning name into :1'
returning into v_temp;
end;
However, needing to dynamically create tables is normally an indication of a badly designed schema. It shouldn't really be necessary.
I can recommend René Nyffenegger's post "Why is dynamic SQL bad?" for reasons why you should avoid dynamic SQL, if at all possible, from a performance standpoint. Please also be aware that you are much more open to SQL injection and should use bind variables and DBMS_ASSERT to help guard against it.
If you run the program multiple time you will get an error even after modifying the program to run the select statement as dynamic SQL or using a returning into clause.
Because when you run the program first time it will create the table without any issue but when you run it next time as the table already created first time and you don't have a drop statement it will cause an error: "Table already exists in the Database".
So my suggestion is before creating a table in a pl/sql program always check if there is any table with the same name already exists in the database or not. You can do this check using a Data dictionary views /system tables which store the metadata depending on your database type.
For Example in Oracle you can use following views to decide if a tables needs to be created or not:
DBA_TABLES ,
ALL_TABLES,
USER_TABLES

Resources