oracle bulk collect and reading the data - oracle

I have created below proc to read all the data from one table and populate it in a grid in .net form.
CREATE OR REPLACE PROCEDURE EVMPDADM.GETALLBATCHES_ARTICLE_57(p_batchstatus OUT XEVMPD_SUBMITTEDBATCH%ROWTYPE )
IS
TYPE batch_status IS TABLE OF XEVMPD_SUBMITTEDBATCH%ROWTYPE INDEX BY PLS_INTEGER;
l_batchstatus batch_status;
BEGIN
SELECT * BULK COLLECT INTO l_batchstatus FROM XEVMPD_SUBMITTEDBATCH ;
FOR i IN 1..l_batchstatus.count LOOP
p_batchstatus:= l_batchstatus(i);
END LOOP;
END GETALLBATCHES_ARTICLE_57;
To test if the proc is running fine I tried to print the data by using below Pl-sql block:
DECLARE
v_batchstatus XEVMPD_SUBMITTEDBATCH%ROWTYPE;
BEGIN
EVMPDADM.GETALLBATCHES_ARTICLE_57(v_batchstatus);
DBMS_OUTPUT.PUT_LINE( v_batchstatus.Batch_id || ' ' || v_batchstatus.BATCH_DESCRIPTION || ' ' || v_batchstatus.STATUS || ' ' ||v_batchstatus.RECORD_STATUS || ' ' ||v_batchstatus.NUMBER_OF_RECORDS);
END;
/
But from this process I am getting the last row only.
I want to print all the records present in the table.
can any one please help me to figure out what is wrong in the above code.

The error messages are very obvious. You are calling your procedures with:
Wrong number of arguments for EVMPDADM.GETALLBATCHES_ARTICLE_57: It has one OUT parameter. So you need to pass that parameter.
Wrong type of argument for DBMS_OUTPUT.PUT_LINE: It has one IN VARCHAR2 parameter, and not XEVMPD_SUBMITTEDBATCH%ROWTYPE. Read here
So, it should be this way:
DECLARE
v_batchstatus XEVMPD_SUBMITTEDBATCH%ROWTYPE;
BEGIN
v_batchstatus:= EVMPDADM.GETALLBATCHES_ARTICLE_57(v_batchstatus);
--use DBMS_OUTPUT.PUT_LINE for every column of XEVMPD_SUBMITTEDBATCH separately after you convert them to varchar2 if they are not.
END;
/
Besides, the procedure this way will return only the last row. So you might want to change that.
If you want to print all the records from the table, you need to add DBMS_OUTPUT.PUT_LINE inside the loop, it will become like this:
FOR i IN 1..l_batchstatus.count LOOP
p_batchstatus:= l_batchstatus(i);
dbms_output.put_line( p_batchstatus.col1 || ' ' || p_batchstatus.col2 || ... );
END LOOP;
Where col1, col2, ... are the columns names of XEVMPD_SUBMITTEDBATCH given they are of the type VARCHAR2. Or you will need extra processing

Related

Oracle pl/sql Array

let's see if somebody can help me, I need to delete rows from different tables and I did think to do it using an array so i wrote this :
DECLARE
TYPE mytype_a IS TABLE OF VARCHAR2(32) INDEX BY BINARY_INTEGER;
mytype mytype_a;
BEGIN
mytype(mytype.count + 1) := 'MYTABLE';
FOR i IN 1 .. mytype.count
LOOP
DELETE mytype(i) WHERE valid = 'N';
END LOOP;
END;
Trying to run this piece of code using sqldeveloper I get the ORA-00933 command not properly ended, if I put directly the table name it works, what am I doing wrong?
Thank you.
Thank you very much guys, it works perfectly.
This is not the correct approach. You have to use Dynamic SQL for this -
DECLARE
type mytype_a is table of varchar2(32) index by binary_integer;
mytype mytype_a;
stmt varchar(500) := NULL;
BEGIN
mytype (mytype.count + 1) := 'MYTABLE';
for i in 1..mytype.count loop
stmt := 'DELETE FROM ' || mytype(i) || ' where valid =''N''';
EXECUTE IMMEDIATE stmt;
end loop;
END;
You would need to use dynamic SQL, concatenating the table name from the collection into the statement, inside your loop:
execute immediate 'DELETE FROM ' || mytype(i) || ' where valid = ''N''';
Or you can put the statement into a variable so you can display it for debugging purposes, and then execute that, optionally with a bind variable for the valid value:
stmt := 'DELETE FROM ' || mytype(i) || ' where valid = :valid';
dbms_output.put_line(stmt);
execute immediate stmt using 'N';
dbms_output.put_line('Deleted ' || sql%rowcount || ' row(s)');
... which I've made also display how many rows were deleted from each table. Note though that you shoudln't rely on the caller being able to see anything printed with dbms_output - it's up to the client whether it shows it.
The whole anonymous block would then be:
DECLARE
type mytype_a is table of varchar2(32) index by binary_integer;
mytype mytype_a;
stmt varchar2(4000);
BEGIN
mytype (mytype.count + 1) := 'MYTABLE';
for i in 1..mytype.count loop
stmt := 'DELETE FROM ' || mytype(i) || ' where valid = :valid';
dbms_output.put_line(stmt);
execute immediate stmt using 'N';
dbms_output.put_line('Deleted ' || sql%rowcount || ' row(s)');
end loop;
END;
/
You could use a built-in collection type to simplify it even further.
db<>fiddle showing some options.
Hopefully this doesn't apply, but if you might have any tables with quoted identifiers then you would need to add quotes in the dynamic statement, e.g.:
stmt := 'DELETE FROM "' || mytype(i) || '" where valid = :valid';
... and make sure the table name values in your collection exactly match the names as they appear in the data dictionary (user_tables.table_name).

PL SQL Record Operations

Hi I am working on an academic assignment and need some help setting up records:
Write a PL/SQL block to print information about a publisher.
Declare a PL/SQL record based on the structure of the bk_publishers table.
In the declarative section, use the %ROWTYPE attribute and declare the variable publisher_record of type bk_publisher.
In the executable section, get all the information from the bk_publishers table by using publ_id and put it in your record. Display the publ_id and publ_name from the record using a cursor for loop.
Reference Database Chart
So far I have been able to write a block that outputs the contents, but I don't know how to get the contents of the record to print.
Any insights would be very helpful!
Thanks
SET SERVEROUTPUT ON
SET VERIFY OFF
DECLARE
TYPE bk_record IS RECORD
(publ_id bk_publishers.publ_id%TYPE,
publ_name bk_publishers.publ_name%TYPE);
publisher_record bk_publishers%ROWTYPE;
CURSOR bk_cur IS
SELECT * FROM bk_publishers;
BEGIN
OPEN bk_cur;
FETCH bk_cur INTO publisher_record;
CLOSE bk_cur;
FOR publ_no in bk_cur
LOOP
DBMS_OUTPUT.PUT_LINE(publ_no.publ_id || ' ' || publ_no.publ_name);
END LOOP;
END;
/
A simple RECORD variable can hold the contents of a single row, so you have to display column values of individual rows within a loop.
DECLARE
TYPE bk_record IS RECORD ( publ_id bk_publishers.publ_id%TYPE,
publ_name bk_publishers.publ_name%TYPE );
publisher_record bk_publishers%rowtype;
CURSOR bk_cur IS SELECT *
FROM bk_publishers;
BEGIN
OPEN bk_cur;
LOOP
FETCH bk_cur INTO publisher_record;
EXIT WHEN bk_cur%notfound; --Condition to exit the loop.
dbms_output.put_line(publisher_record.publ_id
|| ' ' || publisher_record.publ_name);
END LOOP;
CLOSE bk_cur;
END;
/

Display a table inside an Oracle procedure

I'm on Oracle DB 12c and using SQL Developer.
How can I display every rows of a table inside a procedure, if all arguments are "null".
I'm guessing that my IF is correct and I might have seen two or three posts where they used cursors but I'm not very familiar with the utilization of those.
I would like it to basically be a SELECT * FROM Salle but with a condition.
Am I on the right track here ?
CREATE OR REPLACE PROCEDURE Foo1 (noSalle in varchar2, Cat in varchar2, Nb in number)
IS
cursor SYS_REFCURSOR; -- Not sure at all about that
BEGIN
DBMS_OUTPUT.PUT_LINE('Salle : ' || noSalle || 'Cat : ' || Cat);
IF (noSalle = null AND Cat = null AND Nb = null) THEN
OPEN cursor FOR
SELECT * from Salle;
-- Some sort of FOR row IN cursor LOOP ?
-- Display ALL rows of "Salle"
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Erreur Oracle : '||sqlcode||' ; Message Oracle : '||sqlerrm);
END;
SYS_REFCURSOR is used to hold tabular data usually used when you want to return such data from a function.
Null comparison is incorrect. Use colname is null instead.
If you just want to print all the rows using dbms_output.put_line or something similar, you can do this
for row in (select * from salle) loop
dbms_output.put_line(row.col1||' '||row.col2);
end loop;

Is this a table of tables in PL/SQL (If not what is going on with this code?)

Can someone clarify what the PL/SQL code below is doing? It looks as if assets_type is a table of base_Asset. Does that make it a Table of Tables?
I'm having a difficult time visualizing this when it comet to populating the data:
assets(v_ref_key)(dbfields(i).field) := rtrim(replace(strbuf_long2,'''',''''''));
Is this similar to a two dimensional array? Does this mean to populate the field column in the assets (temporary) table with an index of v_ref_key?
PROCEDURE LOAD
IS
TYPE dbfields_rec IS RECORD (field dbfields.field%TYPE,
article_title dbfields.title%TYPE,
image_title dbfields.title%TYPE);
TYPE dbfields_type IS TABLE OF dbfields_rec INDEX BY BINARY_INTEGER;
TYPE base_Asset IS TABLE OF VARCHAR2(4000) INDEX BY VARCHAR2(32);
TYPE assets_type IS TABLE OF asset_type INDEX BY VARCHAR2(4000);
dbfields dbfields_type;
assets assets_type;
v_ref_key assets.ref_key%TYPE;
-- CLIPPED Populate dbfields array code
-- It correctly populates
FOR i IN 1..dbfields.COUNT LOOP
BEGIN
sqlbuf := '(select rtrim(ufld3), ' || dbfields(i).field ||
' as col_label from assetstable ' ||
' where rtrim(ufld3) = ' || '''' || in_id || '''' || ' )';
OPEN assets_cur FOR
sqlbuf;
LOOP
FETCH assets_cur INTO v_ref_key, strbuf_long2;
EXIT WHEN assets_cur%NOTFOUND;
IF (trim(strbuf_long2) is not null and dbfields(i).field is not null) THEN
assets(v_ref_key) (dbfields(i).field)
:= rtrim(replace(strbuf_long2,'''',''''''));
END IF;
END LOOP;
close assets_cur;
END;
END LOOP;
END LOAD;
PL/SQL really only provides one-dimensional arrays - but each element of the array is allowed to be another array if you want to make arrays that act like multi-dimensional ones.
Here is an awfully contrived example to illustrate:
DECLARE
TYPE rows_type IS TABLE OF VARCHAR2(4000) INDEX BY VARCHAR2(4000);
TYPE spreadsheet_type IS TABLE OF row_type INDEX BY VARCHAR2(4000);
spreadsheet spreadsheet_type;
BEGIN
spreadsheet ('row 1') ('column A') := 'XYZ';
END;
The first ('row 1') is the index into the spreadsheet_type array, which would hold all the columns for a particular "row"; and the second ('column A') is the index into the rows_type array.
The "multi-dimensional" aspect of this implementation isn't perfect, however: while you can work with a whole row if you want, e.g.:
my_row rows_type;
...
my_row := spreadsheet ('row 1');
you can't pick out a particular column - there's no way to refer to the set of all elements in the rows for a particular index into rows_type. You'd have to do something like make another type and loop through the first array.

Is it possible to parameterize a query inside pl sql?

The stored procedures being written here currently concats the parameters to the queries:
SELECT *
FROM Names
WHERE Name = ' || prmName || '
ORDER BY ' || prmSortField
Is it possible to parameterize this query inside the stored procedure? Possibly like:
query = 'select * From Names Where Name = #name Order By ' || prmSortField
call(query, prmName)
Note: In case you wonder why we do so, there are two common parameters for our sp's: sortFieldIndex and sortDirection. Since we cannot directly parameterize these, the query is dynamically generated. But other parameters make the queries open for injection. So I am looking a way to parameterize some of the parameters.
Absolutely. Use cursors.
DECLARE
CURSOR c1 (job VARCHAR2, max_wage NUMBER) IS
SELECT * FROM employees WHERE job_id = job AND salary > max_wage;
BEGIN
FOR person IN c1('CLERK', 3000)
LOOP
-- process data record
DBMS_OUTPUT.PUT_LINE('Name = ' || person.last_name || ', salary = ' ||
person.salary || ', Job Id = ' || person.job_id );
END LOOP;
END;
For a dynamic query with bind values, do this:
procedure p (prmName varchar2, prmSortField varchar2)
is
query varchar2(100);
rc sys_refcursor;
names_rec names%rowtype;
begin
query = 'select * From Names Where Name = :name Order By ' || prmSortField
open rc for query using prmName;
loop
fetch rc into names_rec;
exit when rc%notfound;
-- process this row
end loop;
close rc;
end;
For a more elaborate procedure that supports optional parameter values (but uses sys context), check out the following post on Asktom.com
PRATTY -- Thanks for the question regarding 'CURSOR'...

Resources