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;
/
Related
I know that in order to print something on sqlplus like below:
begin
dbms_output.put_line('Hello!');
end;
/
I need to call
set serveroutput on;
before that.
I also know that is not needed, but I can also call
DBMS_OUTPUT.enable;
before, just in case. This is working for me.
But what if I want to keep printing the progress of a long loop? It seems impossible to me. I've tried everything to print some progress on the loop below but just doesn't work. Is there some way of doing that? I even tried to spool to a file and didn't work.
Note 1: I can't truncate or partition this table as the DBA doesn't want to help me with that, so I have to use this nasty loop...
Note 2: I've noticed that once the loop is done, the whole output is printed. Looks like oracle is buffering the output and printing everything at the end. I'm not sure how to avoid that and print on every loop iteration.
set serveroutput on;
declare
e number;
i number;
nCount number;
f number;
begin
DBMS_OUTPUT.enable;
dbms_output.put_line('Hello!');
select count(*) into e from my_big_table where upd_dt < to_date(sysdate-64);
f :=trunc(e/10000)+1;
for i in 1..f
loop
delete from my_big_table where upd_dt < to_date(sysdate-64) and rownum<=10000;
commit;
DBMS_OUTPUT.PUT_LINE('Progress: ' || to_char(i) || ' out of ' || to_char(f));
end loop;
end;
Thank you for any answer.
There are 2 standard ways for such things:
set module and action in your session DBMS_APPLICATION_INFO.SET_MODULE:
SQL> exec DBMS_APPLICATION_INFO.SET_MODULE('my_long_process', '1 from 100');
PL/SQL procedure successfully completed.
SQL> select action from v$session where module='my_long_process';
ACTION
----------------------------------------------------------------
1 from 100
set session_longops:
DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS
I'd recommend it in your case since that is exactly designed for long operations.
Example on Oracle-Base.
----
PS: dbms_output,put_line saves all output in a collection (nested table) variable of dbms_output package, so you can't get it from another session and client can't get it during user call (execution). In addition to set serveroutput on you can also get the output using dbms_output.get_lines: http://orasql.org/2017/12/10/sqlplus-tips-8-dbms_output-without-serveroutput-on/
Btw, in case if you need to filter or analyze output from dbms_output, sometimes it's convenient to get output in a query, so you can use filter strings in where clause or aggregate them: https://gist.github.com/xtender/aa12b537d3884f4ba82eb37db1c93c25
DBMS_OUTPUT will only ever be displayed after the PL/SQL code has terminated and control has returned to the calling program.
Output is, as you found, buffered. When your PL/SQL code finishes, then the calling program (e.g. SQL*Plus) can go and fetch that output.
Insert into another table, maybe call it "MYOUTPUT".
Create the table:
create table myoutput (lineno number, outline varchar2(80));
Add this after your delete:
insert into MYOUTPUT values (i,'Progress: ' || to_char(i) || ' out of ' || to_char(f));
Then select from MYOUTPUT periodically to see progress.
select outline from myoutput order by lineno;
Bobby
You can use UTL_FILE to write output to an external file, as in:
DECLARE
fh UTL_FILE.FILE_TYPE;
nRow_count NUMBER := 0;
BEGIN
fh := UTL_FILE.FOPEN('DIRECTORY_NAME', 'some_file.txt', 'w');
FOR aRow IN (SELECT *
FROM SOME_TABLE)
LOOP
nRow_count := nRow_count + 1;
IF nRow_count MOD 1000 = 0 THEN
UTL_FILE.PUT_LINE(fh, 'Processing row ' || nRow_count);
UTL_FILE.FFLUSH(fh);
END IF;
-- Do something useful with the data in aRow
END LOOP; -- aRow
UTL_FILE.FCLOSE_ALL; -- Close all open file handles, including
-- the ones I've forgotten about...
END;
Table : WSH_DEL_DETAILS_INTERFACE
Unique Column:DELIVERY_DETAIL_INTERFACE_ID
Input to procedure : DELIVERY_DETAIL_INTERFACE_ID
Column values to be fetched:SALES_ORDER_LINE_NUMBER , SALES_ORDER_NUMBER
Expected Output:
Single record
Actual Output:
All records in table are being fetched
Code:
create or replace PROCEDURE procedurevalidation(
delivery_detail_interface_id IN
WSH_DEL_DETAILS_INTERFACE.DELIVERY_DETAIL_INTERFACE_ID%TYPE,
ROW_COUNT OUT INTEGER)
IS
CURSOR wddi_cur IS SELECT * FROM WSH_DEL_DETAILS_INTERFACE WHERE
DELIVERY_DETAIL_INTERFACE_ID = delivery_detail_interface_id;
wddi_record WSH_DEL_DETAILS_INTERFACE%ROWTYPE;
BEGIN
OPEN wddi_cur;
LOOP
FETCH wddi_cur into wddi_record;
EXIT when wddi_cur%NOTFOUND;
DBMS_OUTPUT.ENABLE(100000);
DBMS_OUTPUT.PUT_LINE(delivery_detail_interface_id);
DBMS_OUTPUT.PUT_LINE('SALESORDERNUMBER111:::: ' ||
wddi_record.SALES_ORDER_NUMBER);
DBMS_OUTPUT.PUT_LINE('SALESORDERLINENUMBER1111::::: ' ||
wddi_record.SALES_ORDER_LINE_NUMBER);
DBMS_OUTPUT.PUT_LINE('COUNT' || ROW_COUNT);
END LOOP;
CLOSE wddi_cur;
end;
You need to change the names of the input variable to your procedure.
create or replace PROCEDURE procedurevalidation(
p_delivery_detail_interface_id IN
WSH_DEL_DETAILS_INTERFACE.DELIVERY_DETAIL_INTERFACE_ID%TYPE,
ROW_COUNT OUT INTEGER)
And in your cursor you need to change the variable name as well.
CURSOR wddi_cur
IS
SELECT *
FROM WSH_DEL_DETAILS_INTERFACE
WHERE DELIVERY_DETAIL_INTERFACE_ID = p_delivery_detail_interface_id;
Your cursor is returning all records in the table because you are equating the table's column itself and not matching it with the input variable in the procedure
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
I have a PL/SQL file that has a loop structure.
The script is as follows.
SET SERVEROUTPUT ON
declare
c_id employee.id%type;
c_name employee.name%type;
c_address employee.address%type;
CURSOR c_employee is
SELECT id, name, address from employee;
begin
open c_employee;
LOOP
FETCH c_employee into c_id, c_name, c_address;
EXIT when c_employee%notfound;
dbms_output.put_line(c_id||' '||c_name||' '||c_address);
END LOOP;
close c_employee;
end;
/
When I run this from SQLPlus I get only the details of the first row but not the rest. What am I doing wrong? How to get all the outputs for the loop.
Try to convert your code to use a for loop instead of the open statement, like so -
for r_employee in c_employee
LOOP
dbms_output.put_line(r_employee.c_id||' '||r_employee.c_name||' '||r_employee.c_address);
END LOOP;
Where r_employee is a variable of employee%type.
The way you currently wrote it does not iterate through the cursor, and this is why only the first row is presented.
Even though your code looks correct, it should iterate through all the
row not just one. Try to use below snippet and run it in SQL plus if
still single row then there may be some other issue.
SET SERVEROUTPUT ON
DECLARE
BEGIN
FOR I IN
(SELECT id, name, address FROM employee
)
LOOP
dbms_output.put_line(I.ID||' '||I.name||' '||I.address);
END LOOP;
END;
/
I'm trying to get every result of a query to then print an output and make other query with the result. I'm trying to make it with a Cursor. But when I try to print the query result it says me:
PLS-00306: wrong number or types of arguments in call to 'PUT_LINE'
My code is:
DECLARE
-- Store the SELECT query in a cursor
CURSOR l_cur IS select memname from emuser.DEF_TABLES#controlm t, emuser.DEF_JOB#controlm j where (t.TABLE_ID = j.TABLE_ID) and t.sched_table = 'DWHRAC_DIARIOS2_DC2';
--Create a variable that will hold each result from the cursor
l_cur_rec l_cur%ROWTYPE;
BEGIN
-- Open the Cursor so that we may retrieve results
OPEN l_cur;
LOOP
-- Get a result from the SELECT query and store it in the variable
FETCH l_cur INTO l_cur_rec;
-- EXIT the loop if there are no more results
EXIT WHEN l_cur%NOTFOUND;
-- INSERT INTO another table that has the same structure as your results
DBMS_OUTPUT.PUT_LINE( l_cur_rec);
END LOOP;
-- Close the cursor to release the memory
CLOSE l_cur;
END;
Could you help me please?
Thanks
DBMS_OUTPUT.PUT_LINE accepts a single string as a parameter, but here it is being passed a variable of type l_cur%ROWTYPE which is not allowed. You should change the call to PUT_LINE to specify the name of the column(s) you want to print, such as:
DBMS_OUTPUT.PUT_LINE(l_cur_rec.MEMNAME);
Share and enjoy.