storing rows from table using pl/sql - oracle

I have to call a procedure multiple times that then populates a table. Problem is the procedure truncates the table after each call. I have to store the results of the table for each run. I looked up the documentation and couldnt get an idea how to do this in pl/sql. Any ideas is much appreciated.
thanks a lot!

After each call of the procedure, copy the resulting data into another table with the same columns:
INSERT INTO TABLE_B
SELECT *
FROM TABLE_A;
When you're finished calling the procedure, all your data is in TABLE_B.
In PL/SQL, it looks like this:
BEGIN
FOR I IN 1..10 LOOP
PROC(I);
INSERT INTO TABLE_B
SELECT *
FROM TABLE_A;
END LOOP;
PROCESS_ALL_DATA();
END;
Update:
If you don't have permissions to create tables, then you could store the partial results in a PL/SQL table (in memory):
DECLARE
TYPE T_T_A IS TABLE OF A%TYPE;
L_IMED_TABLE T_T_A;
BEGIN
FOR I IN 1..10 LOOP
PROC(I);
SELECT * BULK COLLECT INTO L_IMED_TABLE
FROM A;
END LOOP;
FOR I IN L_IMED_TABLE.FIRST .. L_IMED_TABLE.LAST LOOP
PROCESS_RESULT_ROW( L_IMED_TABLE(I) );
END LOOP;
END;

You can have trigger that gets triggered on insert to the main table and populates the same data to a archive table, where you can add more columns like timestamp and call counter and more.

Related

How to insert records into variables from cte in oracle?

I have a procedure in which I want to fetch all records from cte into Names variable. But this code is not writing into names from CTE. How can I fetch records into names so that I can later loop through names and get content of field_name?
CREATE OR REPLACE PROCEDURE sp_market
IS
Names VARCHAR2(32767);
BEGIN
WITH CTE(sqql) As
(
SELECT field_name sqql FROM pld_medicare_config
)
SELECT sqql into Names from CTE;
END sp_market;
SELECT sqql into Names from CTE;
You are assigning multiple rows returned from table to a variable, which will fail.
You could simply use a CURSOR FOR LOOP which will create an implicit cursor and you can loop through the names:
CREATE OR REPLACE PROCEDURE sp_market IS
BEGIN
FOR i IN (
SELECT field_name
FROM pld_medicare_config
)
LOOP
-- Your logic goes here
dbms_output.put_line(i.field_name);
END LOOP;
END;
/
I think your best bet is to create a associative array and use BULK COLLECT to populate the table. In its simplest form, the code would look like this:
CREATE OR REPLACE PROCEDURE sp_market IS
TYPE lt_names IS TABLE OF VARCHAR2(32767) INDEX BY PLS_INTEGER;
l_tNames lt_names;
BEGIN
SELECT field_name
BULK COLLECT INTO l_tNames
FROM pld_medicare_config
IF l_tNames.COUNT() > 0 THEN
FOR i IN l_tNames.FIRST..l_tNames.LAST LOOP
NULL; --REPLACE WITH YOUR LOGIC
END LOOP;
END IF;
END;
/
A few notes:
I'm assuming that you've set MAX_STRING_SIZE to EXTENDED. Otherwise, you'll have an issue with VARCHAR2 that big.
As I said, that is the simplest way to do this. If you're expecting a huge result set, you'll want to look into chunking it up. This Oracle blog post is very helpful in giving you multiple options for how to perform bulk processing. (Blog Post)

Result of Stored Procedure save in table variable

I have question: I have stored procedure A(return three out paramters). I want to call procedure A in loop and insert these three parameters into temporaty table and return this table.
DECLARE
Type TestTable IS TABE OF NUMBER; -- for example one parameter!!!
myTable TestTable;
BEGIN
LOOP
A(o_param1, o_param2, o_param3);
-- myTable insert o_param1,2,3;
-- insert into myTable values(99); - here I have error PL/SQL: ORA-00942: table or view does not exist
END LOOP;
SELECT * FROM myTable;
END;
I dont know how to do -- myTable insert o_param1,2,3;. Please help me.
write insert statement inside the loop. so for each loop you can have the values inserted to the table and give a commit after the loop.
But you cannot have a select * from table inside the anonymous block. Remove that from the block and after end; you can try running select * from table to see the output.
BEGIN
LOOP
A(o_param1, o_param2, o_param3);
-- myTable insert o_param1,2,3;
insert into myTable values (o_param1, o_param2, o_param3);
END LOOP;
commit;
--SELECT * FROM myTable;-
END;
SELECT * FROM myTable;
> Blockquote
First, you cannot insert data into myTable directly (insert into myTable) because Oracle table types, declared in a declare section of the script, are not visible in sql statements (exception - insert using 'bulk collect' with types, declared in Oracle dictionary).
Even if you insert data in myTable using myTable(idx)... you can not select it outside the script because myTable exists only inside the script.
I think the simpliest way is to create usual table or global temporary table. If you will use global temporary table create it with 'ON COMMIT PRESERVE ROWS' (if you use commit after insert)

Oracle Stored procedure - execute for all the select result

Say I have a stored procedure which accepts 2 varchars, does some processing and updates my business tables. Is there a way that I can run the stored procedure for the results from a select query?
Like,
execute my_stored_proc select varchar_1,varchar_2 from an_ip_table;
You can iterate over results by loop
BEGIN
FOR RECS IN (SELECT varchar_1, varchar_2 FROM an_ip_table)
LOOP
my_stored_proc (RECS.varchar_1, RECS.varchar_2);
END LOOP;
END
This could be a simple way:
begin
for i in (
select varchar_1, varchar_2
from an_ip_table
)
loop
my_stored_proc(i.varchar_1, i.varchar_2);
end loop;
end;
Initially, I thought of just to put a comment, but this needs some explanation, so I'm writing an answer. You are actually doing it the wrong way. Ideally, you should be passing a cursor to your my_stored_proc and fetching the cursor inside the procedure. Your method actually causes multiple calls to procedure for every row from the query result. The processing will be very slow if you have huge volume of data. It is a bad idea even if there are few rows.
Here is a sample procedure that does a dml operation using FORALL.It is just a sample, but you should be able to convert your select query such that you should be able to do dml this way.
CREATE OR REPLACE PROCEDURE my_stored_proc (
p_iptab_cur SYS_REFCURSOR
) AS
TYPE iprec IS RECORD ( col1 an_ip_table.col1%TYPE,
col2 an_ip_table.col1%TYPE );
TYPE iptype IS
TABLE OF iprec;
ips iptype;
BEGIN
FETCH p_iptab_cur BULK COLLECT INTO ips;
FORALL i IN ips.FIRST..ips.LAST
--Your DML-- using the collection of records.
END;
/
--Calling the procedure by passing the `CURSOR`
DECLARE
x SYS_REFCURSOR;
BEGIN
OPEN x FOR select col1, col2
from an_ip_table;
my_stored_proc(x);
END;
/

Declare Table Variable in Oracle Procedure

I'm having a heck of a time trying to find an example of this being done. I have a procedure, and as part of that procedure I want to store the results of a SELECT statement so that I can work against that set, and then use it as a reference to update the original records when it's all done.
The difficulty I'm having is in declaring the temporary table variable. Here's an example of what I'm trying to do:
PROCEDURE my_procedure
IS
output_text clob;
temp_table IS TABLE OF MY_TABLE%ROWTYPE; -- Error on this line
BEGIN
SELECT * BULK COLLECT INTO temp_table FROM MY_TABLE WHERE SOME_DATE IS NULL;
-- Correlate results into the clob for sending to email (working)
-- Set the SOME_DATE value of the original record set where record is in temp_table
I get an error on the second occurrence of IS, saying that it is an unexpected symbol. This suggests to me that my table variable declaration is either wrong, or in the wrong place. I've tried putting it into a DECLARE block after BEGIN, but I just get another error.
Where should this declaration go? Alternatively, if there is a better solution I'll take that too!
CREATE OR REPLACE PROCEDURE PROCEDURE1 AS
output_text clob;
type temp_table_type IS TABLE OF MY_TABLE%ROWTYPE;
temp_table temp_table_type;
BEGIN
SELECT * BULK COLLECT INTO temp_table FROM MY_TABLE;
END PROCEDURE1;
or
CREATE OR REPLACE PROCEDURE PROCEDURE1 ( output_text OUT clob ) IS
type temp_table_type IS TABLE OF MY_TABLE%ROWTYPE
INDEX BY BINARY_INTEGER;
temp_table temp_table_type;
BEGIN
SELECT * BULK COLLECT INTO temp_table FROM MY_TABLE;
FOR indx IN 1 .. temp_table.COUNT
LOOP
something := temp_table(indx).col_name;
END LOOP;
END PROCEDURE1;
I had a similiar problem and found this:
Selecting Values from Oracle Table Variable / Array?
The global temporary table can be used like a regular table, but its content is only temporary (deleted at end of session/transaction) and each session has its own table content.
If you don't need dynamic SQL this can be used as good solution:
CREATE GLOBAL TEMPORARY TABLE temp_table
(
column1 NUMBER,
column2 NUMBER
)
ON COMMIT DELETE ROWS;
PROCEDURE my_procedure
IS
output_text clob;
BEGIN
-- Clear temporary table for this session (to be sure)
DELETE FROM temp_table;
-- Insert data into temporary table (only for this session)
INSERT INTO temp_table SELECT * FROM MY_TABLE WHERE SOME_DATE IS NULL;
-- ...
END;
The only disadvantages are, in my opinion, that you got another table and that the temporary table is not dynamic.

how to generate a table of random data from existing database table through oracle procedure

I have to generate a table (contains two columns) of random data from a database table through oracle procedure. The user can indicate the number of data required and we have to use the table data with ID values from 1001 to 1060. I am trying to use cursor loop and not sure dbms_random method dhould I use.
I am using the following code to create procedure
create or replace procedure a05_random_plant(p_count in number)
as
v_count number := p_count;
cursor c is
select plant_id, common_name
from ppl_plants
where rownum = v_count
order by dbms_random.value;
begin
delete from a05_random_plants_table;
for c_table in c
loop
insert into a05_random_plants_table(plant_id, plant_name)
values (c_table.plant_id, c_table.common_name);
end loop;
end;
/
it complied successfully. Then I executed with the following code
set serveroutput on
exec a05_random_plant(5);
it shows anonymous block completed
but when run the following code, I do not get any records
select * from a05_random_plants_table;
The rownum=value would not work for a value greater than 1
hence try the below
create or replace procedure a05_random_plant(p_count in number)
as
v_count number := p_count;
cursor c is
select plant_id, common_name
from ppl_plants
where rownum <= v_count
order by dbms_random.value;
begin
delete from a05_random_plants_table;
for c_table in c
loop
insert into a05_random_plants_table(plant_id, plant_name)
values (c_table.plant_id, c_table.common_name);
end loop;
end;
/
Query by Tom Kyte - will generate almost 75K of rows:
select trunc(sysdate,'year')+mod(rownum,365) TRANS_DATE,
mod(rownum,100) CUST_ID,
abs(dbms_random.random)/100 SALES_AMOUNT
from all_objects
/
You can use this example to write your query and add where clause to it - where id between 1001 and 1060, for example.
I don't think you should use a cursor (which is slow naturally) but do a direct insert from a select:
insert into table (col1, col2)
select colx, coly from other_table...
And, isn't missing a COMMIT on the end of your procedure?
So, all code in your procedure would be a DELETE, a INSERT WITH that SELECT and then a COMMIT.

Resources