PL SQL Functions Exception handling [duplicate] - oracle

When executing the following code, it just says the procedure is completed and doesn't print the infomation i want it to (firstName, lastName) and then the other values from the select query in a table below.
CREATE OR REPLACE PROCEDURE PRINT_ACTOR_QUOTES (id_actor char)
AS
CURSOR quote_recs IS
SELECT a.firstName,a.lastName, m.title, m.year, r.roleName ,q.quotechar from quote q, role r,
rolequote rq, actor a, movie m
where
rq.quoteID = q.quoteID
AND
rq.roleID = r.roleID
AND
r.actorID = a.actorID
AND
r.movieID = m.movieID
AND
a.actorID = id_actor;
BEGIN
FOR row IN quote_recs LOOP
DBMS_OUTPUT.PUT_LINE('a.firstName' || 'a.lastName');
end loop;
END PRINT_ACTOR_QUOTES;
/
When setting server output on, I get
a.firstNamea.lastName
a.firstNamea.lastName
a.firstNamea.lastName
a.firstNamea.lastName
multiple times!

What is "it" in the statement "it just says the procedure is completed"?
By default, most tools do not configure a buffer for dbms_output to write to and do not attempt to read from that buffer after code executes. Most tools, on the other hand, have the ability to do so. In SQL*Plus, you'd need to use the command set serveroutput on [size N|unlimited]. So you'd do something like
SQL> set serveroutput on size 30000;
SQL> exec print_actor_quotes( <<some value>> );
In SQL Developer, you'd go to View | DBMS Output to enable the DBMS Output window, then push the green plus icon to enable DBMS Output for a particular session.
Additionally, assuming that you don't want to print the literal "a.firstNamea.lastName" for every row, you probably want
FOR row IN quote_recs
LOOP
DBMS_OUTPUT.PUT_LINE( row.firstName || ' ' || row.lastName );
END LOOP;

Ensure that you have your Dbms Output window open through the view option in the menubar.
Click on the green '+' sign and add your database name.
Write 'DBMS_OUTPUT.ENABLE;' within your procedure as the first line.
Hope this solves your problem.

Set Query as below at first line
SET SERVEROUTPUT ON

this statement
DBMS_OUTPUT.PUT_LINE('a.firstName' || 'a.lastName');
means to print the string as it is.. remove the quotes to get the values to be printed.So the correct syntax is
DBMS_OUTPUT.PUT_LINE(a.firstName || a.lastName);

For SQL Developer
You have to execute it manually
SET SERVEROUTPUT ON
After that if you execute any procedure with DBMS_OUTPUT.PUT_LINE('info'); or directly .
This will print the line
And please don't try to add this
SET SERVEROUTPUT ON
inside the definition of function and procedure, it will not compile and will not work.

In Oracle SQL Developer, you can follow steps by steps as the below image:

I am using Oracle SQL Developer,
In this tool, I had to enable DBMS output to view the results printed by dbms_output.put_line
You can find this option in the result pane where other query results are displayed.
so, in the result pane, I have 7 tabs. 1st tab named as Results, next one is Script Output and so on. Out of this you can find a tab named as "DBMS Output" select this tab, then the 1st icon (looks like a dialogue icon) is Enable DBMS Output. Click this icon. Then you execute the PL/SQL, then select "DBMS Output tab, you should be able to see the results there.

All of them are concentrating on the for loop but if we use a normal loop then we had to use of the cursor record variable. The following is the modified code
CREATE OR REPLACE PROCEDURE PRINT_ACTOR_QUOTES (id_actor char)
AS
CURSOR quote_recs IS
SELECT a.firstName,a.lastName, m.title, m.year, r.roleName ,q.quotechar from quote q, role r,
rolequote rq, actor a, movie m
where
rq.quoteID = q.quoteID
AND
rq.roleID = r.roleID
AND
r.actorID = a.actorID
AND
r.movieID = m.movieID
AND
a.actorID = id_actor;
recd quote_recs%rowtype;
BEGIN
open quote_recs;
LOOP
fetch quote_recs into recs;
exit when quote_recs%notfound;
DBMS_OUTPUT.PUT_LINE(recd.firstName||recd.lastName);
end loop;
close quote_recs;
END PRINT_ACTOR_QUOTES;
/

Related

My long time SQL*Plus loop doesn't print DBMS_OUTPUT.PUT_LINE output during execution

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;

Viewing the value of the variable in Oracle Sql Developer

I am compeletely new to Oracle-PLSQL. I have to convert a TSQL function to PLSQL. So I need to declare variable, set values inside of it and use them. This is a very very simple code:
declare LoopCounter INT ;
begin
Select MIN(RankNumber) into LoopCounter
From
(
Select Substation , ColumnTitle,S6_name,AVNR
,Rank() Over(Order By Substation , ColumnTitle,S6_name) RankNumber
From PREREPORT
) RankGroup;
end;
This Code now is being tested in Sql Developer. How can I check the Variable LoopCounter ?
I have set the SET SERVEROUTPUT ON and used the DBMS_OUTPUT.PUT_LINE(LoopCounter); for displaying the value of the value but nothing has been shown.
Thanks
In SQL-Developer choose View/dbms output option. The dbms-output pane should appear somwhere in the window.
Next click a big green plus icon in this pane, and select your active session there. This session shoul appear in this pane, see the printscreen below
Next execute the procedure - just hit Ctrl-Enter to run it. This is my test procedure:
DECLARE
x int;
BEGIN
SELECT count(*) INTO x
FROM dual;
DBMS_OUTPUT.PUT_LINE( x );
END;
/
when the procedure is done, you should see the result of DBMS_OUTPUT.PUT_LINE command in the DBMS-output pane:
[
I have used same code but with Different table it Works perfectly. I would Suggest to check SQL Statement Separately if you are able to get some result.(Checked the Code in LiveSQL.oracle.com)
declare
LoopCounter INT ;
begin
Select MIN(RankNumber) into LoopCounter
From
(
Select ename , Job,mgr
,Rank() Over(Order By ename , job,mgr) RankNumber
From scott.emp
) RankGroup;
dbms_output.put_line(Loopcounter);
end;

Oracle Stored Procedure posing a prob

[EDIT]Editing the code to reflect changes coming from comments
I have a problem with one of the stored procedures I'm trying to create in an Oracle database.
The goal is to update every table which has an indiv column.
CREATE OR REPLACE PROCEDURE sp_majUserOnAllK (lastU IN VARCHAR2, newU IN VARCHAR2)
AS
BEGIN
FOR item IN (
select table_name , owner
from all_tab_columns
where column_name = 'INDIV' AND OWNER ='K'
)
LOOP
EXECUTE IMMEDIATE 'UPDATE K.' || item.table_name || ' SET indiv = :newValue WHERE indiv = :oldValue' USING newU, lastU;
END LOOP;
END sp_majUserOnAllK;
exec sp_majUserOnAllK( 'hum','hum');
Problem is, when I try to execute the stored procedure, I got an error message with no detail at all ('non valid SQL').
I tried taking the code out of the stored procedure. And there, it works. Only the beginning is changing to :
DECLARE
newU NVARCHAR2(50);
lastU NVARCHAR2(50);
req VARCHAR2(100);
CURSOR ctable IS
select table_name , owner from all_tab_columns where column_name = 'INDIV' AND OWNER ='KEXPLOIT';
BEGIN
newU := 'hum';
lastU := 'hum';
FOR item IN ctable
....
Like that, it works perfectly and does exactly what it is supposed to do.
As the only difference is the assignation of the variable, I think I may have a problem with my procedure declaration but I can't find a solution. The compilation is ok.
Any idea ?
Your procedure's syntax is not correct. Try this.
CREATE OR REPLACE PROCEDURE sp_majUserOnAllK (lastU IN VARCHAR2, newU IN VARCHAR2)
IS
req VARCHAR2(100);
BEGIN
FOR item IN (select table_name , owner from all_tab_columns where column_name = 'INDIV' AND OWNER ='K')
LOOP
req := 'UPDATE K.' || item.table_name || ' SET indiv = :newValue WHERE indiv = :oldValue';
EXECUTE IMMEDIATE req USING newU, lastU;
END LOOP;
-- return 1; -- note: procedures do not return values
END;
/
A five-second Google search on "dbeaver exec command" brought this up among the first few hits:
https://github.com/dbeaver/dbeaver/issues/749
In it, we learn that EXEC is not supported by dbeaver.
EXEC is an SQL*Plus command. It is not Oracle SQL, and it is not PL/SQL. SQL*Plus is a shell program of sorts for interacting with Oracle databases; it has its own language, distinct from SQL and PL/SQL.
SQL Developer and Toad (and perhaps other similar programs) support (most of) SQL*Plus, but apparently dbeaver (with which I am not familiar) does not.
The link I copied above suggests using the CALL command instead. See the link for examples.
As an aside, when we use EXEC in SQL*Plus and SQL Developer, there is no semicolon at the end of the procedure call. Adding an unnecessary semicolon, however, does not throw an error (SQL*Plus is, apparently, smart enough to simply ignore it).

Creating Oracle PL/SQL Stored procedure

I'm trying to convert the SQL Query to Oracle PL/SQL stored procedure.
Here is the query:
select * from table1 where DATE = " + s1 + " and TYPE='" + ty + "' and NAME='"+nm+"' Order by TYPE DEsc;
Here is the Stored Procedure:
CREATE PROCEDURE procedure1
(
s1 IN DATE,
ty IN CHAR DEFAULT 2,
nm IN VARCHAR2 DEFAULT 64
)
IS
d table1.DATE%TYPE;
C table1.TYPE%TYPE;
S table1.NAME%TYPE;
CURSOR tb IS select DATE,TYPE,NAME INTO d,c,s from table1;
BEGIN
FOR i IN tb
LOOP
DBMS_OUTPUT.PUT_LINE('DATE' ||i.DATE);
DBMS_OUTPUT.PUT_LINE('TYPE' ||i.TYPE);
DBMS_OUTPUT.PUT_LINE('NAME' ||i.NAME);
END LOOP;
END procedure1;
I do not see any output after Executing Stored procedure. I'm not sure if I have created the stored procedure correctly.
"I do not see any output after Executing Stored procedure"
Your "output" is DBMS_OUTPUT which is for displaying text to a screen. However, by default it writes the text to a buffer, and we need to enable the output to see the contents of the buffer.
How to do this varies depending on which client you're using. In SQL*Plus it's
SQL> set serveroutput on
In an IDE like TOAD, PLSQL Developer or Oracle SQL Developer there's a separate DBMS_OUTPUT tab: click on the tab and enable output (there's a button) - or set Preferences to always have it on.
DBMS_OUTPUT is rarely a useful means for returning data in an actual application. The normal approach is to use a Ref Cursor, which maps to JDBC and ODBC ResultSet classes. Something like this:
CREATE OR REPLACE PROCEDURE procedure1
(
s1 IN DATE,
ty IN CHAR DEFAULT 2,
nm IN VARCHAR2 DEFAULT 64,
rc out sys_refcursor
)
IS
BEGIN
open rc for
select * from table1
where d = s1
and c = ty
and s = nm;
END procedure1;
/
Incidentally, your parameters are defined with string datatypes but the defaults are numeric values. Please don't get into bad habits. Strong datatyping is a key defence against data corruption and broken code, so always use the correct data type.
try this;
CREATE PROCEDURE PROCEDURE1 (
S1 IN DATE,
TY IN CHAR DEFAULT 2,
NM IN VARCHAR2 DEFAULT 64
)
IS
BEGIN
FOR I IN (SELECT DATE, TYPE, NAME FROM TABLE1)--Easier way to use cursor
LOOP
DBMS_OUTPUT.PUT_LINE ('DATE' || I.DATE);
DBMS_OUTPUT.PUT_LINE ('TYPE' || I.TYPE);
DBMS_OUTPUT.PUT_LINE ('NAME' || I.NAME);
END LOOP;
END PROCEDURE1;
by executing this you only created the procedure and stored it in db, you need to call it and turn on system output to see the output. like this:
set serveroutput on;
begin
PROCEDURE1(null, null, null);
end;
What environment are using to compile your code? You should certainly be seeing some immediate feedback.
Note that in most environments, though, you need to do a little more than you did before.
The final ";" in your code is part of PL/SQL. It does not trigger execution of your DDL. Generally you should do this:
CREATE OR REPLACE PROCEDURE myproc
IS
BEGIN
...
END myproc;
/
And that "/" will submit your statement for execution.

Retrieve a select count(*) in Oracle inside a cursor

I need to retrieve the number of rows in a SELECT COUNT(*) statement that is inside a cursor (in Oracle).
The following code should explain it clearly:
PROCEDURE Save(CF_CURSOR OUT "VPA"."CF_#Runtime".CF_CURSOR_TYPE) AS
V_CF_CURSOR "VPA"."CF_#Runtime".CF_CURSOR_TYPE;
CF_ROWCOUNT NUMBER;
BEGIN
OPEN V_CF_CURSOR FOR
SELECT COUNT(*) INTO CF_ROWCOUNT FROM (
SELECT * FROM "VPA"."Employee" -- returns 1 row
) WHERE ROWNUM <= 1;
IF(CF_ROWCOUNT = 0) THEN
-- DO SOMETHING BUT NEVER GOES HERE
END IF;
COMMIT;
CF_CURSOR := V_CF_CURSOR;
END;
Here, the value of CF_ROWCOUNT is never set. If I remove the cursor, everything works as expected. I have tried to use SQL%ROWCOUNT, but it does not work either.
And, I cannot remove the cursor...
Thanks in advance!
Have you tried opening the cursor - which does a COUNT(*), then fetching that into the CF_ROWCOUNT variable instead of doing it as an INTO within the ref-cursor statement.
For example:
OPEN V_CF_CURSOR FOR SELECT COUNT(*) FROM "VPA"."Employee"; -- returns 1 row
FETCH V_CF_CURSOR INTO CF_ROWCOUNT;

Resources