In SQL/Developer, when I execute a statement I get a Script Output message that reads something like 7 Records Merged
Here's my relevant PL/SQL Code:
v_sql_loader := 'merge into foobar b using foobiz i on (b.foobar_id = i.foobiz_id) when not matched then insert (foobar_id) values (foobiz_id)';
execute immediate v_sql_loader;
How can I capture 7 records Merged in PL/SQL?
I'm writing dbms_output.put_line(SQLERRM) but that only returns
ORA-0000: normal, successful completion
What Oracle/PLSQL object can I use to replicate SQL/Developer Script Output messages?
Desired Results: PLSQL Statement, preferably dbms_output.put_line();that indicates 7 Records Merged.
Use SQL%ROWCOUNT:
BEGIN
...
EXECUTE IMMEDIATE v_sql_loader;
DBMS_OUTPUT.PUT_LINE('Merged: ' || SQL%ROWCOUNT);
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;
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;
/
For some reason I'm trying to figure out why the following query executes by full table scan which takes ages because the table has ~31M rows
PROCEDURE d1(k_uni_in IN data_par.k_uni%TYPE) AS
CURSOR d1_cur IS
SELECT d.*
FROM data_par d
WHERE d.k_uni = k_uni_in
ORDER BY d.k_date;
BEGIN
FOR i IN d1_cur LOOP
...
END LOOP;
END;
However seemingly similar query runs index range scan and is pretty much instant
PROCEDURE d1(k_uni_in IN data_par.k_uni%TYPE) AS
CURSOR d1_cur(k_cv IN data_par.k_uni%TYPE) IS
SELECT d.*
FROM data_par d
WHERE d.k_uni = k_cv
ORDER BY d.k_date;
BEGIN
FOR i IN d1_cur(k_uni_in) LOOP
...
END LOOP;
END;
Why does that happen? Should I always use cursor parameters instead of using suprogram parameters in cursors?
If your table DATA_PAR has a column named K_UNI_IN, then Oracle is interpreting this line:
WHERE d.k_uni = k_uni_in
As meaning
WHERE d.k_uni = d.k_uni_in
And, since that's obviously not a condition that an index can help with, you're getting a full table scan.
See also: http://docs.oracle.com/cd/E11882_01/appdev.112/e25519/nameresolution.htm#LNPLS2038
I'm building a procedure which would require to get an input from user to print few details. But when I use & to get values it fails with errors. the logic is as follows..
DBMS_OUTPUT.PUT_LINE('Enter Y to display Unauthorized records OR N to skip the display');
--SELECT &1 INTO lv_choice FROM DUAL;
IF NOT ('&lv_choice'='Y') THEN
DBMS_OUTPUT.PUT_LINE ('RECORDS WILL NOT BE DISPLAYED');
ELSE
DBMS_OUTPUT.PUT_LINE ('RECORDS TO BE DISPLAYED ARE:');
......
I have tried using &1 into dual or directly calling &lv_choice which is failing with PLSQL internal errors.
Any methods to get input from user to proceed further in the procedure?
This isn't possible in PL/SQL - PL/SQL doesn't have access to the terminal(unless you do something like plug in Java or call your program from a something like SQL*Plus(in which you can use commands like ACCEPT/PROMPT before you run the procedure).
The & variables are substitution variables, and are specific to SQL*Plus, not PL/SQL
If you are using some UI Terminal like SQLDeveloper or TOAD, you can achieve it using below code:
CREATE OR REPLACE INPUTPROCEDURE (LV_CHOICE IN VARCHAR2)
AS
BEGIN
DBMS_OUTPUT.PUT_LINE('Enter Y to display Unauthorized records OR N to skip the display');
--SELECT &1 INTO lv_choice FROM DUAL;
IF lv_choice <> 'Y' THEN
DBMS_OUTPUT.PUT_LINE ('RECORDS WILL NOT BE DISPLAYED');
ELSE
DBMS_OUTPUT.PUT_LINE ('RECORDS TO BE DISPLAYED ARE:');
END INPUTPROCEDURE;
And Invoke the above Procedure like below:
DECLARE
dyn_stmt VARCHAR2(200);
b BOOLEAN := TRUE;
BEGIN
dyn_stmt := 'BEGIN INPUTPROCEDURE(:LV_CHOICE); END;';
EXECUTE IMMEDIATE dyn_stmt USING b;
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.