Executing a variable in oracle - plsql

The below procedure compiled successfully. But, when I try to run the its getting error.
CREATE OR REPLACE PROCEDURE SAMPLE_PROCEDURE
AS
VARIABLE1 VARCHAR2(2000);
BEGIN
VARIABLE1:='DECLARE A TIMESTAMP:=LOCALTIMESTAMP;
CREATE GLOBAL TEMPORARY TABLE TEMP_BWXROW
(ROW_ID NUMBER(10),DIVISION VARCHAR2(256),OUTLET VARCHAR2(256),CLASS VARCHAR2(256));';
EXECUTE IMMEDIATE VARIABLE1;
END;
Error is:
6550. 00000 - "line %s, column %s:\n%s"
*Cause: Usually a PL/SQL compilation error.
*Action:
Can you help me, what is wrong in this.

Very strange to be dynamically creating a global temporary table. Anyway, I assume this is all part of a learning exercise ...
Try this:
CREATE OR REPLACE PROCEDURE SAMPLE_PROCEDURE
AS
VARIABLE1 VARCHAR2(2000);
BEGIN
VARIABLE1:='DECLARE A TIMESTAMP:=LOCALTIMESTAMP;
BEGIN
CREATE GLOBAL TEMPORARY TABLE TEMP_BWXROW
(ROW_ID NUMBER(10),
DIVISION VARCHAR2(256),
OUTLET VARCHAR2(256),
CLASS VARCHAR2(256));
END';
EXECUTE IMMEDIATE VARIABLE1;
END;

What's wrong with this is that you almost certainly shouldn't be creating a table at runtime and you almost certainly shouldn't be using dynamic PL/SQL and you really, really, really shouldn't be creating a table dynamically inside a dynamic PL/SQL block.
If you are absolutely determined to do so, the CREATE TABLE statement would itself need to use dynamic SQL inside of the dynamic PL/SQL block. If I've got all my quotes escaped correctly, you'd end up with something like this
CREATE OR REPLACE PROCEDURE SAMPLE_PROCEDURE
AS
VARIABLE1 VARCHAR2(2000);
BEGIN
VARIABLE1:='DECLARE
A TIMESTAMP:=LOCALTIMESTAMP;
BEGIN
EXECUTE IMMEDIATE ''CREATE GLOBAL TEMPORARY TABLE TEMP_BWXROW
(ROW_ID NUMBER(10),
DIVISION VARCHAR2(256),
OUTLET VARCHAR2(256),
CLASS VARCHAR2(256))'';
END;';
EXECUTE IMMEDIATE VARIABLE1;
END;
If I came across a piece of code doing this in one of my systems, though, I would have a very strongly worded conversation with the original developer to understand what possessed them to believe that any problem necessitated PL/SQL executing a dynamic PL/SQL block that itself executed a dynamic SQL statement.

Related

How to correctly make a procedure in Pl/SQL in which I create a TABLE and use a CURSOR

The assignment I am trying to do is
"Create a procedure that places the names of all presidents who were born in one specific
state, in a temporary table. Display the contents of this table."
The procedure complies but when I try to invoke it, it gives me:
00000 - "table or view does not exist"
Error(8,5): PLS-00103: Encountered the symbol "CREATE" when expecting one of the following: begin function pragma procedure subtype type current cursor delete exists prior
I have been stuck for a while now. Does anybody know what I am doing wrong?
My code so far is:
CREATE OR REPLACE PROCEDURE stateofpresident(p_state president.state_born%TYPE)
AS
CURSOR c_state IS
SELECT *
FROM president;
BEGIN
execute immediate 'CREATE TABLE presidentFromState;
(
president_name VARCHAR2
)';
FOR r_state IN c_state LOOP
IF(p_state = r_state.state_born) THEN
execute immediate 'INSERT INTO presidentFromState VALUES(r_state.pres_name)';
commit;
END IF;
END LOOP;
execute immediate 'DROP TABLE presidentFromState';
END stateofpresident;
/
SET SERVEROUT ON
BEGIN
stateofpresident('VIRGINIA');
END;
/
SELECT *
FROM presidentFromState;
The immediate cause of your error is the semi-colon (;) at "presidentFromState;" At run fhat terminates the statement and the SQL interpreter at that point does not know what is want, the create syntax is invalid. The statement compiles because at compile time it is a properly formatted string. That is why dynamic SQL should be avoid if at all possible. Your script also has an additional error. Your last select will fail as the table presidentFromState ws not only created but also dropped in the procedure. Finally, just an FYI, the entire FOR cursor and the cursor itself is entirely unnecessary, the entire operation can be completed is one statement: Look into the structure
Insert into table_name(columns)
Select columns ...
Since this obviously an assignment or tutorial I'll leave the exact for your research.

PLSQL: No output displayed when using dynamic query inside Stored Procedure

I have been asked to create an SP which creates temporary table and insert some records.
I am preparing some sample code for the same as mentioned below but the output is not displayed.
create or replace procedure Test
is
stmt varchar2(1000);
stmt2 varchar2(1000);
begin
stmt := 'create global temporary table temp_1(id number(10))';
execute immediate stmt;
insert into temp_1(id) values (10);
execute immediate 'Select * from temp_1';
execute immediate 'Drop table temp_1';
commit;
end;
When i am executing the SP by (Exec Test) desired O/P is not displayed.
I am expecting O/P of "Select * from temp_1" to be displayed. But it is not happening. Please suggest where i am doing wrong.
But i am interesting in knowing why ( execute immediate 'Select * from temp_1';) do not yield any result
For two reasons. Firstly because as #a_horse_with_no_name said PL/SQL won't display the result of a query. But more importantly here, perhaps, the query is never actually executed. This behaviour is stated in 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 would have to execute immediate into a variable, or more likely a collection if your real scenario has more than one row, and then process that data - iterating over the collection in the bulk case.
There is not really a reliable way to display anything from PL/SQL; you can use dbms_output but that's more suited for debugging than real output, and you usually have no guarantee that the client will be configured to show whatever you put into its buffer.
This is all rather academic since creating and dropping a GTT on the fly is not a good idea and there are better ways to accomplish whatever it is you're trying to do.
The block you showed shouldn't actually run at all; as you're creating temp_1 dynamically, the static SQL insert into temp_1 will error as that table does not yet exist when the block is compiled. The insert would have to be dynamic too. Any dynamic SQL is a bit of a warning sign you're maybe doing something wrong, though it is sometimes necessary; having to do everything dynamically suggests the whole approach needs a rethink, as does creating objects at runtime.

compilation issue with execute immediate in Forall statement

Please help me in resolving below issue i am facing, i have to insert data into a table(table name genereted using variable value and table is created already) within FORALL..
Declare
TYPE dept_data_rec IS RECORD
(
Dept_no number,
Dept_name varchar2(100),
Dept_loc Varchar2(20)
);
TYPE nt_dept_data IS TABLE OF dept_data_rec ;
l_dept_data_nt nt_dept_data;
BEGIN
FORALL j IN 1..l_dept_data_nt.COUNT SAVE EXCEPTIONS
EXECUTE IMMEDIATE 'INSERT INTO '||l_get_dept_rec.dept_seq_no||'_Dept_Data VALUES '||
l_dept_data_nt(j);
COMMIT;
while compiling this code i am getting below error:
PLS-00306: wrong number or types of arguments in call to '||'
However when code using actual table name it works
FORALL j IN 1..l_dept_data_nt.COUNT SAVE EXCEPTIONS
INSERT INTO A1_dept_data VALUES
l_dept_data_nt(j);
COMMIT;
Oracle 10g -
In versions of Oracle prior to 11g, you can't use FORALL with EXECUTE IMMEDIATE, only with INSERT, UPDATE, or DELETE.
See http://docs.oracle.com/cd/B13789_01/appdev.101/b10807/13_elems021.htm
It's a special syntax
that reads like a FOR loop but isn't, and
is used by PL/SQL to perform bulked DML operations and only with the exact keyword, not with dynamic SQL or any other code.
Oracle 11g +
In 11g, the restriction on using EXECUTE IMMEDIATE was lifted. See http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/forall_statement.htm
However, the only variables allowed in the string are subscripted elements from a single array in the USING clause.
The documentation is unclear whether you can dynamically "change" the table per row using the FORALL syntax. Remember that the FORALL is used by PL/SQL to perform a bulk DML operation and that needs to go to one table for this to yield any performance benefit.
Best performance solution for the above problem
You should make two levels of arrays, the first defines which table and the second defines the data for that table.
Use an ordinary FOR loop over the table array and inside that loop use the special FORALL syntax to perform all the DML for the one table.

Dynamic SQL and Cursor related issue

I have declared cursor and used in the procedure body, then I have dynamic sql statement which creates a table on the fly. After that I need to access the same cursor which i declared.
When I try to open the cursor before the execution of dynamic sql statement its working fine.
When I try to open the cursor after the execution of dynamic sql statement its not opening and cursor.
Please help me.
Thank you.
create or replace procedure(columns varchar2)
is
column_names varchar2(100);
sql_query varchar2(200);
begin
select pk_cols into column_names
from rules where rule_column=columns;
sql_query:='create global temporary table ('||column_names||')';
execute immediate sql_query;
end;
Creating the table is DDL which in Oracle results in an implicit commit, ending your transaction.
To solve this problem you could create the table inside an autonomous transaction:
-- open cursor
declare
pragma autonomous_transaction;
begin
execute immediate 'create table ...';
end;
-- do more with your cursor
For more information about autonomous transactions, see this overview on Tim Hall's excellent site.

Execute Immediate

Can any one help me to to find out the error.
create or replace procedure sample
is
begin
DECLARE AGG_COLUMNS VARCHAR2(2000);
BEGIN
EXECUTE IMMEDIATE 'SELECT COLUMNS FROM COLUMN_NAMES' INTO AGG_COLUMNS;
END;
begin
EXECUTE IMMEDIATE
'CREATE TABLE NEW_BW_COLUMN_ROW_CELL_JOIN AS
(
SELECT *
FROM BW_COLUMN_ROW_CELL_JOIN
PIVOT
(
MAX(STRING_VALUE)
FOR COLUMN_NAME IN ('||AGG_COLUMNS||')))';
END;
end;
Error(9,5): PL/SQL: Statement ignored
Error(17,36): PLS-00201: identifier 'AGG_COLUMNS' must be declared
Thanks
The immediate error is that the local variable AGG_COLUMNS is declared in the first nested PL/SQL block. That means that it is out of scope as soon as the first nested block completes. You cannot, therefore, use it in the second nested PL/SQL block. You can fix that by declaring the local variable in your procedure's declaration section. You can also get rid of the nested PL/SQL blocks
create or replace procedure sample
is
AGG_COLUMNS VARCHAR2(2000);
begin
EXECUTE IMMEDIATE 'SELECT COLUMNS FROM COLUMN_NAMES' INTO AGG_COLUMNS;
EXECUTE IMMEDIATE
'CREATE TABLE NEW_BW_COLUMN_ROW_CELL_JOIN AS
(
SELECT *
FROM BW_COLUMN_ROW_CELL_JOIN
PIVOT
(
MAX(STRING_VALUE)
FOR COLUMN_NAME IN ('||AGG_COLUMNS||')))';
end;
This should remove the immediate compilation error. I'm not sure, though, whether that resolves all your problems.
COLUMN_NAMES isn't a table in a default Oracle install. This would have to be something that you created in order for this code to run.
If you did create the COLUMN_NAMES table and COLUMNS stores a comma-separated string, then there is no need to use dynamic SQL to query the table. You can do a simple SELECT ... INTO.

Resources