Dynamic SQL and Cursor related issue - plsql

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.

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.

Executing procedure in plsql developer

I am totally new to PLSQL and I am struggling to execute a procedure in PLSQL Developer. I have created a procedure named as 'employee' as follows:
CREATE OR REPLACE PROCEDURE employee IS
var_name VARCHAR2(20) := 'Parkavi';
var_web VARCHAR2(20) := 'parkavi.com';
BEGIN
DBMS_OUTPUT.PUT_LINE('Hi! I am ' ||var_name|| 'from' ||var_web);
END employee;
Now I need to execute this procedure so that I can view the output. Please help me out. Thanks in advance!!
In PL/SQL Developer, you execute PL/SQL blocks in the Test Window.
File > New > Test Window will provide a template block something like this:
declare
begin
end;
You just need to add your procedure name (and remove the unneeded declare section as you have no variables), so it's:
begin
employee;
end;
Alternatively, right-click on the procedure name and select 'Test' from the pop-up menu, and it will generate the above block for you.
If the expected dbms_output text is not displayed in the 'Output' tab, the first thing to check is that the 'Enabled' checkbox is checked.
To diagnose dbms_output, the simplest test case would be just:
begin
dbms_output.put_line('Hello');
end;

Does TCL statements come under implicit cursors?

Does TCL statements come under implicit cursors if they are not declared explicitly? link. Or is COMMIT a PL/SQL statement?
A SQL (implicit) cursor is opened by the database to process each SQL statement that is not associated with an explicit cursor.
set serveroutput on
DECLARE
row_var test%rowtype;
BEGIN
savepoint a;
execute immediate 'delete from test';
DBMS_OUTPUT.PUT_LINE ('No. of deleted '||sql%rowcount);
if (sql%rowcount=0) then
DBMS_OUTPUT.PUT_LINE ('CP1:');
end if;
/*Select * into row_var from test;
DBMS_OUTPUT.PUT_LINE ('No. of after delete '||row_var.testcol);*/
commit; //TCL statment
END;
Select * from test
COMMIT is part of the SQL language. SQL Doc
"Use the COMMIT statement to end your current transaction and make permanent all changes performed in the transaction. A transaction is a sequence of SQL statements that Oracle Database treats as a single unit. This statement also erases all savepoints in the transaction and releases transaction locks."
And can be invoked in a PL/SQL block as a static SQL statement. PL/SQL Doc
"The COMMIT statement makes permanent any changes made to the database during the current transaction. A commit also makes the changes visible to other users....The SQL COMMIT statement can be embedded as static SQL in PL/SQL."

Ending PLSQL procedure

I wrote a PLSQL procedure in Oracle APEX, but I don't know how to end it as every way I have tried it still complains.
DECLARE
PROCEDURE FzgZuordnen(Volt VARCHAR2) IS
Variable Declarations
*
BEGIN
*
END;
FzgZuordnen END;
I have also tried
*
END;
END;
But it doesn't seem to like any way I end my procedure. I have ended all of the things inside the procedure.
Thanks for any help.
You can declare a local procedure in a PL/SQL block anywhere - including in APEX. The syntax is like this:
DECLARE
PROCEDURE FzgZuordnen(Volt VARCHAR2) IS
-- Variable Declarations
BEGIN
-- Procedure code
END FzgZuordnen;
BEGIN
-- Block PL/SQL that calls the procedure
END;
For example:
DECLARE
PROCEDURE raise_error (error_text VARCHAR2) IS
BEGIN
raise_application_error (-20001, error_text);
END FzgZuordnen;
BEGIN
if :p1_value < 0 then
raise_error ('Value cannot be negative');
elsif :p1_value > 10 then
raise_error ('Value cannot exceed 10');
end if;
END;
Because the procedure is declared locally it can only be used from the PL/SQL block where it is declared. If you needed a procedure that could be called from many placed in your application or page then it would need to be defined in the database (preferably in a package).
To my knowledge you cannot place PL/SQL procedures directly in an APEX page. For PL/SQL execution there are APEX processes. If you have to re-use your code on other pages then either copy the process to each page or use a db procedure (meaning putting the procedure directly in the database)
Using APEX process:
Create a new Process on the Page and select "PL/SQL Code" as type. Then type your Code into the APEX process.
Variable Declarations
*
BEGIN
*
END;
Processes can only be used inside the same page. If you want to use your code on multiple other pages you have to copy them to this page.
Using DB-procedure:
If you use a db procedure you have to add it directly to the oracle database. Therefor connect to the database with a tool of your choice. Execute your code from above. To call the procedure in APEX use something like this.
begin
PKG.FzgZuordnen(:APEX_PAGEITEM);
end;
try this way:
DECLARE
PROCEDURE FzgZuordnen(Volt VARCHAR2) IS
Variable Declarations
*
BEGIN
*
END FzgZuordnen;
BEGIN
*
END;
You can create a plsql procedure inside a database schema using sql developer or sql plus
create or replace procedure zgZuordnen(Volt VARCHAR2) IS
.. variable declaration
begin
{statament blocks}
end zgZuordnen;
From APEX frontend developer option you can call the procedure with bind variable

Executing a variable in oracle

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.

Resources