PL/SQL procedure with For Loop - sql

I am rather new to PL/SQL and am trying to understand how to code for this issue.
I need to create 130 identical Tables, in 130 different Schemas using 130 different Tablespaces. I can readily run the code, then do global Search/Replace for the next schema, run the code, and repeat.
What I want to do is write an anonymous block with
declare n number(3);
Begin
for n in 1..130
Loop
(run my statements)
End Loop;
End;
/
Currently the statements I am using is a straight SQL:
CREATE TABLE xyz_101.... Tablespace xyz_101
I am thinking I should create variables to hold all the Create Table, Alter Table, Create Index, Create Synonym syntax, then execute immediate this variables. I am not completely certain how to do this as I will need pass "n" to each execution.
Is there a better way? Should I write the "Create Table", Create Index", "Create Synonym" statements as cursors and then execute the cursors?
I am certain someone else has solved this problem and appreciate any guidance or insight.
Thank you!

Use EXECUTE IMMEDIATE.
for n in 1 .. 130 loop
execute immediate 'create table t'||n||' ( dummy char(1) )';
end loop;

Related

PLSQL Procedure to Truncate and Re-populate table

I have some tables and views in my schema and I am trying to create a stored procedure that will take in 2 parameters (table_name, view_name) to Truncate a table and re-populate it from a view.
Here is the code I have for the procedure:
CREATE OR REPLACE
PROCEDURE PROC_NAME (TABLE_NAME IN VARCHAR2, VIEW_NAME IN VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE TABLE_NAME';
EXECUTE IMMEDIATE 'INSERT INTO TABLE_NAME
SELECT * FROM VIEW_NAME';
END;
/
Now when I run the following code:
BEGIN
PROC_NAME('SOME_TABLE', 'SOME_VIEW');
END;
/
I get the following error:
ORA-00942: table or view does not exist
ORA-06512: at "SCHEMA.PROC_NAME", line 4
ORA-06512: at line 2
00942. 00000 - "table or view does not exist"
What do you guys think is the issue?
Thanks in advance!
Try:
CREATE OR REPLACE
PROCEDURE PROC_NAME (TABLE_NAME IN VARCHAR2, VIEW_NAME IN VARCHAR2)
IS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE '||TABLE_NAME;
EXECUTE IMMEDIATE 'INSERT INTO '||TABLE_NAME||'
SELECT * FROM '||VIEW_NAME;
END;
/
Your basic problem is that you had passed the parameters correctly but had not used them in the procedure. The fix was to used the the concatenation operaterator || in the strings used by EXECUTE IMMEDIATE to combine the the parameters into the string being executed.
An additional option is to use DELETE FROM rather than TRUNCATE TABLE. When Oracle first implemented Materialised Views, which is a grown up version of what you are trying to achieve, they made the same mistake. TRUNCATE TABLE is very quick but in the Oracle implementation it is a DDL (Data Definition Language) statement which means it will complete with an implicit commit. Therefore, for a period of time until the INSERT completes (and is committed), your table will be empty. If Oracle thought it important enough to change their underlying technique, then you should consider doing the same.
If you do not change to the DELETE technique then you should adding a COMMIT at the end of your procedure. The use of TRUNCATE TABLE will guarantee the removal of the data is committed, so if your INSERT succeeds then you should also commit that statement.
My reference to Materialised Views is relevant as it is a potential a built-in replacement for what you are trying to write for yourself. The problem with it is that it has so many bells and whistles that it is difficult to find an article on how to use it in your simple use case. I would welcome a comment referencing such an article.

Combining a block query and an usual query in oracle sql

Hey I'm new to Oracle SQL but I'm a frequent user of PostGreSQL and SQL Server. I'm currently trying to run a query that will materialize a table every time I run the query. The actual application is more complicated but here is the general idea:
declare
v_exists number:=0;
BEGIN
select count(1)
into v_exists
from all_tables
where table_name = 'FFF';
if v_exists >0 then
EXECUTE IMMEDIATE 'DROP TABLE FFF';
dbms_output.put_line('Table dropped');
end if;
END;
/
create table fff as
select *
from my_table;
Both blocks of code work if I run them separately but when I run them together it doesn't work. Is there a way to combine these kind of queries in just one script?
Thanks
This is a pattern which is common in SQL Server (and perhaps PostgreSQL too) but which is considered an anti-pattern in Oracle, Oracle provides much better ways of working with data sets than executing DDL on the fly.
One approach is to use PL/SQL collections to cache data in memory. This is suitable when the volumes of data are small, because collections are stored in session memory. Find out more.
Another approach is Global Temporary Tables which are permanent structures with transient data (restricted to scope of transaction or session). Find out more.
The enterprise edition comes with features to pin result sets in memory; this is useful when we want to share the result set across multiple sessions, and the life span of the result set is relatively long (i.e. slowly changing reference data). Find out more.
A further, and perhaps the best, approach is to write efficient queries which obviate the need for caching. DDL is an expensive operation which introduces risk and complexity into applications. The most performative way of doing something is usually to avoid doing it.
Try doing the second as dynamic SQL as well:
declare
v_exists number := 0;
BEGIN
select count(1)
into v_exists
from all_tables
where table_name = 'FFF';
if v_exists >0 then
EXECUTE IMMEDIATE 'DROP TABLE FFF';
dbms_output.put_line('Table dropped');
end if;
EXECUTE IMMEDIATE 'create table fff as select * from my_table';
END;
/
An alternative is a script in SQLPLUS;
WHENEVER SQLERROR CONTINUE
DROP TABLE fff
/
WHENEVER SQLERROR EXIT FAILURE
CREATE TABLE fff
AS SELECT * FROM my_table
/
This will try to drop the table but if it can't will carry on and then try to create the table. If that fails for some reason then the script will fail.

How to delete data from specified tables at once in oracle sql

I have more than 40 tables in RATOR_MONITORING schema for which the table name is starting from 'TEMP_'. I want to delete data from all such tables at once in a single query instead of using delete statement for each and every table. I dont even want to generate statements. I can create anonymous block if required but dont know how to do that. I tried below query but its not working.
Delete from RATOR_MONITORING_CONFIGURATION.'%TEMP_';
If you want to delete all the rows, then better use TRUNCATE, it will reset the high watermark. But remember, truncate is a DDL statement, and thus there will be an implicit commit; With DELETE you can commit manually after validation.
Although, I would not do that in a production environment. If it is something you are doing in test environment to build test data, then you could (ab)use EXECUTE IMMEDIATE.
For example, execute the following anonymous block as RATOR_MONITORING user:
DECLARE
v_sql VARCHAR2(100);
BEGIN
FOR i IN
(SELECT table_name FROM user_tables where table_name like 'TEMP%'
)
LOOP
v_sql := 'TRUNCATE TABLE '||i.table_name;
EXECUTE immediate v_sql;
END LOOP;
END;
/
By the way, using a good text editor, it won't take more than a minute to build DELETE/TRUNCATE statements and do it in pure SQL.

Oracle Sql : Procedure which can create temporary tables inside it

I am new to Oracle Sql and facing an issue :
I want to create a temporary table inside procedure .
LIKE:
CREATE PROCEDURE P
AS
BEGIN
CREATE TEMPORARY TABLE A(ID int);
END P;
BUT THIS IS GIVING ME AN ERROR
How Can I Create a temporary table inside procedure.
I have seen other answers on stackoverflow but that doesn't answer my question properly
Can you please help me out ?
Why do you want to create a temporary table in a stored procedure in the first place?
It is relatively common to create temporary tables in other databases (SQL Server and MySQL, for example). It is very, very rare to do the same thing in Oracle. In almost every case where you are tempted to create a temporary table in Oracle, there is a better architectural approach. There is a thread over on the DBA stack that discusses alternatives to temporary tables and why they are not commonly needed in Oracle.
Programmatically, you can create objects using dynamic SQL
CREATE OR REPLACE PROCEDURE dont_do_this
AS
BEGIN
EXECUTE IMMEDIATE 'CREATE GLOBAL TEMPORARY TABLE a( id INTEGER )';
END;
If you create a temporary table dynamically, however, every reference to that table will also need to be via dynamic SQL-- you won't be able to write simple SELECT statements against the table. And the definition of a temporary table in Oracle is global so it is visible to every session. If you have two different sessions both trying to create the same table, the second session will get an error. If you expect the table to have a different definition in different sessions, you've got even more problems.
You could use Dynamic SQL with EXECUTE IMMEDIATE:
CREATE OR REPLACE
PROCEDURE p
AS
BEGIN
EXECUTE IMMEDIATE 'CREATE TEMPORARY TABLE A(id NUMBER)...etc';
END p;
Edit: Obviously you'll have to ensure your syntax is correct within the EXECUTE IMMEDIATE statement.
Hope it helps.
You must declare your procedure as:
create or replace PROCEDURE MYPROCEDURE AUTHID CURRENT_USER IS
script varchar(4000);
BEGIN
script:= 'CREATE GLOBAL TEMPORARY TABLE BNMCODIAGNOSTICASSOCIE_TEMP
ON COMMIT PRESERVE ROWS
as select ........';
EXECUTE IMMEDIATE script;
commit;
END;

Create/alter from SQL stored procedure

I want to call create table/ alter table command from a procedure. Is it possible?
My requirement is to change the datatype of a column in all tables. So, I am just getting the column name from user_tab_cols. Now I want to create a temp table which requires create statement .. but i am unable to use that within a proc.
Can anyone please help me out?
I presume from the reference to USER_TAB_COLUMNS that this is Oracle. ALTER and CREATE statements are DDL, which we cannot execute directly in PL/SQL. However, there are a couple of ways around this restriction: EXECUTE IMMEDIATE and DBMS_UTILITY.EXEC_DDL(). I will use EXECUTE IMMEDIATE in the following example.
begin
for lrec in ( select table_name from user_tab_columns
where column_name = 'UNIVERSAL_COLUMN_NAME')
loop
execute immediate 'alter table '||lrec.table_name||
' modify UNIVERSAL_COLUMN_NAME varchar2(255)';
end loop;
end;
Note that the usual restrictions apply: the new datatype has to be compatible with the existing datatype (unless the column is empty), and things are trickier with some specilaized datatypes like CLOBs.
edit
I haven't addressed the CREATE TABLE statement. The principle is the same, it is just longer to type out. Besides, I am not entirely clear how it applies to your prior requirement to change the datatype of those columns.
you can generate the query as string and execute it with 'exec' keyword.