I have this procedure to create a table 'circle' and insert some radius and corresponding area to it, this is my code
create or replace procedure table1
is
BEGIN
execute immediate'drop table circle';
execute immediate'create table circle (r int, a int)';
end;
declare
r int;
ar float;
begin
for r in 3 .. 7 loop
ar:=3.14*r*r;
INSERT INTO circle VALUES(r,ar);
end loop;
execute immediate 'select * from circle';
end;
But when I run this I get this warning
Warning: Procedure created with compilation errors.
and when I try to find the table I get
SQL> select * from circle;
select * from circle
*
ERROR at line 1:
ORA-00942: table or view does not exist
what is wrong in my code?
In the code mentioned above, you're just creating a procedure. It also needs to be executed successfully before using the table in anonymous block.
I've created your procedure here and the procedure is created successfully.
Just when you try to execute it, handle the exception for when the table circle doesn't exist in your procedure's code and then execute (or call) it. Further, you could use the anonymous block to insert the values in your table.
If the table doesn't exist, attempting to drop it will fail. The rest of the code won't run, so your table is never created
Carry out your drop attempt and catch the error, then proceed
This answer has more info: Oracle: If Table Exists
Related
I'm a SQL Server DBA currently getting up to speed on Oracle. I'm trying to create something very similar to sp_WhoIsActive for SQL Server but for Oracle without reinventing the wheel. Essentially all I'm doing is selecting some values from v$session and inserting them into a table (poor man's ASH/AWR).
It would seem that in Oracle 12.1, there's a bug when querying dictionary views where it can take forever due to bad parsing logic (Bug 22225899 : SLOW PARSE FOR COMPLEX QUERY). The work-around is to set a session parameter:
alter session set "_optimizer_squ_bottomup"=false;
In T-SQL, I could very easily execute a stored procedure in-session and set this variable at runtime. However in Oracle, it wouldn't seem thats the case.
Sample Code:
CREATE OR REPLACE PROCEDURE SP_DB_ACTIVITY
(
v_temp NUMBER :=1
) IS
BEGIN
alter session set "_optimizer_squ_bottomup"=false;
INSERT INTO SY_DB_ACTIVITY
SELECT
<fields>
FROM
v$session;
commit;
When I run this, I get the error:
"PLS-00103: Encountered symbol 'ALTER' when expecting one of the following..."
Right now, the only way I know how to do this is via a utility like SQL Plus that initiates an interactive user session. Can anyone give me some direction as to how Oracle handles this situation? I'd like to bundle this up into a SP or a Package and then call it from Oracle Scheduler.
Hre is a simple example how to execute alter session inside of the procedure:
CREATE PROCEDURE SP_DB_ACTIVITY IS
BEGIN
EXECUTE IMMEDIATE 'alter session set "_optimizer_squ_bottomup"=false';
END;
/
Here is the way you can combine that with your select and insert statement:
CREATE OR REPLACE PROCEDURE SP_DB_ACTIVITY
(v_temp IN number) AS
v_Id NUMBER;
BEGIN
EXECUTE IMMEDIATE 'alter session set "_optimizer_squ_bottomup"=false';
SELECT 1
INTO v_Id
FROM dual;
INSERT INTO SY_DB_ACTIVITY (id) VALUES(v_Id);
END SP_DB_ACTIVITY;
/
Here is a small DEMO where you can see what will procedure do when you call it and how you can call it. Also, in this example you are calling procedure with and IN parameter. So you can use that parameter for something and in the example above is the procedure without any parameters...
You can also, of course, insert into table directly:
CREATE OR REPLACE PROCEDURE SP_DB_ACTIVITY
(v_temp IN number) AS
v_Id NUMBER;
BEGIN
EXECUTE IMMEDIATE 'alter session set "_optimizer_squ_bottomup"=false';
INSERT INTO SY_DB_ACTIVITY(id)
select 1
from dual;
END SP_DB_ACTIVITY;
/
I've run into problems with following script which I'm trying to execute. In SQLDeveloper or other tools like DataGrip, everything works fine, so in my understanding, this is UCD issue.
...more inserts
insert into M_MIGRATION_CONTROL values ('PRODUCTREL', 'M_' || 'PRODUCTREL');
CREATE OR REPLACE PROCEDURE MIGRATE_DATA_BEFORE_DEPLOY IS
TABLE_NAME VARCHAR2(128);
MIGRATION_TABLE_NAME VARCHAR2(128);
CURSOR MIGRATION_CURSOR IS SELECT * FROM M_MIGRATION_CONTROL;
BEGIN
OPEN MIGRATION_CURSOR;
LOOP
FETCH MIGRATION_CURSOR INTO TABLE_NAME, MIGRATION_TABLE_NAME;
EXIT WHEN MIGRATION_CURSOR%NOTFOUND;
EXECUTE IMMEDIATE 'CREATE TABLE '||MIGRATION_TABLE_NAME||' AS SELECT * FROM '||TABLE_NAME||'';
END LOOP;
CLOSE MIGRATION_CURSOR;
END MIGRATE_DATA_BEFORE_DEPLOY;
/
insert into A_ACCEPTEDINCOMETYPEOPTION select * from M_A_ACCEPTEDINCOMETYPEOPTION;
insert into A_INSTALMENT select * from M_A_INSTALMENT;
...more inserts
with errors:
[sql] Failed to execute: MIGRATION_TABLE_NAME VARCHAR2(128)
[sql] java.sql.SQLSyntaxErrorException: ORA-00900: invalid SQL statement
[sql] Failed to execute: CURSOR MIGRATION_CURSOR IS SELECT * FROM M_MIGRATION_CONTROL
When I print procedure body from Oracle i get:
PROCEDURE MIGRATE_DATA_BEFORE_DEPLOY IS TABLE_NAME VARCHAR2(128)
So I think that client ends create procedure after first ;
Can you help me/advise me, how should this script look like for correct execution?
(Oracle 12.1)
You are using SQL-JDBC plugin for Urban Code Deploy.
According to their documentation/troubleshooting:
The SQL-JDBC plugin does not support deploying stored procedures.
There is a separate SQL*Plus plugin which you may be able to use instead.
I have one create procedure query i m trying to execute it in Oracle Database.Below is the query :
CREATE OR REPLACE PROCEDURE TEST_PROC IS
TYPE TESTTABLE IS TABLE OF a.TEST102%ROWTYPE;
Synatax of the query seems to be fine but when i am executing it is throwing below sql exception.
Encountered the symbol "end-of-file" when expecting one of the following:
. ( # % ; not null range alter character
Trying to find out the issue trying all possible ways from past two days but i did not get any idea wheres the issue is.Can anyone please suggest what is wrong with the query???? Would be great if some one can help me out here.
Procedures must have BEGIN..END block.
Here is a procedure that does not do anything.
CREATE OR REPLACE PROCEDURE TEST_PROC
IS
TYPE TESTTABLE IS TABLE OF dual%ROWTYPE;
BEGIN
NULL;
END;
the following will work:
CREATE TABLE TEST102(id number);
CREATE OR REPLACE PROCEDURE TEST_PROC IS
TYPE TESTTABLE IS TABLE OF TEST102%ROWTYPE;
BEGIN
NULL; -- insert procedure body here
END;
create or replace procedure createtables
Authid current_user as
begin
execute immediate 'create table newcustomer as select * from customer';
end;
create or replace procedure e
is
begin
createtables;
select * from newcustomer;
end;
I got two procedures above. first one will create a new tables called newcustomer, second procedure will call the first procedure and query to the newcustomer table. when I try to compile this code, it says the table is not yet created, I don't really get it as I have called createtables procedure so I assume I have created the table.
Any help will be appreciated. Thanks
Compiling the second procedure without executing the first procedure first will fail, since the table has not been created.
You cannot compile a procedure that relies on objects that do not exist.
Use EXEC createtables before creating procedure e, and do not call createtables in there.
Procedure e will also not compile because you are not using the results of select * from newcustomer as cursor or store the results into variables.
EDIT:
Instead of procedures, you could use an anonymous block. Put the following into a file and execute it (via SQL*Plus for example):
Create Table newcustomer As Select * From customer;
Begin
Null; --# Do something with your new table in here.
End;
/
I have the following procedure:
CREATE PROCEDURE foo ()
SELECT * FROM fooBar INTO TEMP tempTable;
-- do something with tempTable here
DROP TABLE tempTable;
END PROCEDURE;
What happens if there is an exception before the DROP TABLE is called? Will tempTable still be around after foo exits?
If so, foo could fail the next time it is called, because tempTable would already exist. How should that be handled.
EDIT: I am using informix 11.5
According to the documentation, temporary tables are dropped when the session ends.
As others stated, temporary tables last until you drop them explicitly or the session ends.
If the stored procedure fails because the table already exists, SPL generates an exception.
You can deal with exceptions by adding an ON EXCEPTION clause -— but you are entering one of the more baroque parts of SPL, Stored Procedure Language.
Here is a mildly modified version of your stored procedure - one that generates a divide by zero exception (SQL -1202):
CREATE PROCEDURE foo ()
define i integer;
SELECT * FROM 'informix'.systables INTO TEMP tempTable;
-- do something with tempTable here
let i = 1 / 0;
DROP TABLE tempTable;
END PROCEDURE;
execute procedure foo();
SQL -1202: An attempt was made to divide by zero.
execute procedure foo();
SQL -958: Temp table temptable already exists in session.
This shows that the first time through the code executed the SELECT, creating the table, and then ran foul of the divide by zero. The second time, though, the SELECT failed because the temp table already existed, hence the different error message.
drop procedure foo;
CREATE PROCEDURE foo()
define i integer;
BEGIN
ON EXCEPTION
DROP TABLE tempTable;
SELECT * FROM 'informix'.systables INTO TEMP tempTable;
END EXCEPTION WITH RESUME;
SELECT * FROM 'informix'.systables INTO TEMP tempTable;
END;
-- do something with tempTable here
let i = 1 / 0;
DROP TABLE tempTable;
END PROCEDURE;
The BEGIN/END block limits the exception handling to the trapped statement. Without the BEGIN/END, the exception handling covers the entire procedure, reacting to the divide by zero error too (and therefore letting the DROP TABLE work and the procedure seems to run successfully).
Note that temptable still exists at this point:
+ execute procedure foo();
SQL -1202: An attempt was made to divide by zero.
+ execute procedure foo();
SQL -1202: An attempt was made to divide by zero.
This shows that the procedure no longer fails because the temp table is present.
You can limit the ON EXCEPTION block to selected error codes (-958 seems plausible for this one) by:
ON EXCEPTION IN (-958) ...
See the IBM Informix Guide to SQL: Syntax manual, chapter 3 'SPL Statements'.
For Informix 12.10 SPL Statements
For Informix 11.70 SPL Statements
For Informix 11.50 SPL Statements
Note that Informix 11.70 added the 'IF EXISTS' and 'IF NOT EXISTS' clauses to CREATE and DROP statements. Thus, you might use the modified DROP TABLE statement:
DROP TABLE IF EXISTS tempTable;
Thus, with Informix 11.70 or later, the easiest way to write the procedure is:
DROP PROCEDURE IF EXISTS foo;
CREATE PROCEDURE foo()
define i integer;
DROP TABLE IF EXISTS tempTable;
SELECT * FROM 'informix'.systables INTO TEMP tempTable;
-- do something with tempTable here
let i = 1 / 0;
DROP TABLE tempTable; -- Still a good idea
END PROCEDURE;
You could also use this, but then you get the previous definition of the procedure, whatever it was, and it might not be what you expected.
CREATE PROCEDURE IF NOT EXISTS foo()
define i integer;
DROP TABLE IF EXISTS tempTable;
SELECT * FROM 'informix'.systables INTO TEMP tempTable;
-- do something with tempTable here
let i = 1 / 0;
DROP TABLE tempTable; -- Still a good idea
END PROCEDURE;
I finally used a variation of Jonathan's and RET's solution:
CREATE PROCEDURE foo ()
ON EXCEPTION IN (-206)
END EXCEPTION WITH RESUME;
DROP TABLE tempTable;
SELECT * FROM fooBar INTO TEMP tempTable;
-- do something with tempTable here
DROP TABLE tempTable;
END PROCEDURE;
Yes, the temp table will still exist. Temp tables by definition have a lifetime of the session that created them, unless explicitly dropped.
The temp table can only be seen by the session that created it, and there is no impediment to the same procedure being run in parallel by multiple users. Adam's answer to test for the existence of the temp table will return a non-zero result if any user is running the procedure. You need to test that the session that owns the temp table is the current session as well. Given that this question is within the scope of a stored procedure, it might be simpler to add an explicit DROP, wrapped in some exception handling.
SELECT count(*)
INTO w_count
FROM sysmaster:systabnames s,sysmaster:systabinfo i
WHERE i.ti_partnum = s.partnum
AND sysmaster:BITVAL(i.ti_flags,'0x0020') = 1
AND s.tabname = 'tempTable' ;
If w_count is 1, delete table before SELECT ... INTO. Same with DROP TABLE.