Get input from user in PL/SQL procedure - oracle

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;

Related

How to call a stored procedure in pl/sql developer

I am new at this and have a simple question.
I have created a procedure like so in pl/sql developer
CREATE OR REPLACE PROCEDURE myproc2 AS
BEGIN
SELECT cd_desc des, cd_value cd FROM v_codes WHERE cd_type='CVS02'
END;
Now I want to call the procedure and see the output however when I run this
BEGIN
myproc2;
END;
in Pl/sql I am getting an error saying object myproc2 is invalid
How do I call a stored procedure in PL/SQL?
You're calling it right, but the procedure is wrong. If you check its status, it is invalid.
In PL/SQL, a SELECT requires INTO:
CREATE OR REPLACE PROCEDURE myproc2 AS
l_cd_desc v_codes.cd_desc%type;
l_cd_value v_codes.cd_value%type;
BEGIN
SELECT v.cd_desc, v.cd_value
INTO l_cd_desc, l_cd_value
FROM v_codes v
WHERE v.cd_type = 'CVS02';
END;
Beware of possible NO_DATA_FOUND or TOO_MANY_ROWS exception.
Also, although it'll now run OK (I guess), you won't see anything because it is unknown what you'll do next. You could, for example, choose to display values you fetched. In that case, add
<snip>
WHERE v.cd_type = 'CVS02';
dbms_output.put_line(l_cd_desc ||', '|| l_cd_value);
END;
Don't forget to enable serveroutput.
As you commented, you got too_many_rows. How to handle it? It depends on what you want to do. One option is to switch to a cursor FOR loop; now you don't need local variables and - as there's no SELECT statement itself - no INTO clause either:
CREATE OR REPLACE PROCEDURE myproc2
AS
BEGIN
FOR cur_r IN (SELECT v.cd_desc, v.cd_value
FROM v_codes v
WHERE v.cd_type = 'CVS02')
LOOP
DBMS_OUTPUT.put_line (cur_r.cd_desc || ', ' || cur_r.cd_value);
END LOOP;
END;
One great thing about Oracle SQL Developer is the GUI and that it does things for you.
You can open a sheet and run it the traditional way:
BEGIN
PROCEDURENAME(PARAM);
END;
or you can use the GUI, find the object with the (View->) Find DB object, find it, click on it and use the green arrow in the toolbar. It will open a UI for any parameters you used within the procedure.
In SQL Developer, if you want to see the output then you can return a cursor:
CREATE OR REPLACE PROCEDURE myproc2(
o_cursor OUT SYS_REFCURSOR
)
AS
BEGIN
OPEN o_cursor FOR
SELECT cd_desc AS des,
cd_value AS cd
FROM v_codes
WHERE cd_type='CVS02'; -- You need a ; statement terminator here.
END;
/
Then you can use:
-- Declare a cursor bind variable
VARIABLE cur SYS_REFCURSOR;
BEGIN
-- Call the cursor outputting into the bind variable.
myproc2(:cur);
END;
/
-- Print the cursor
PRINT :cur;
And run it as a script (using F5).

How to write an Oracle procedure with a select statement (Specifically on SQL Developer)?

I want to create a simple Oracle Stored procedure on SQL Developer that will return some records on a simple select query. I do not want to pass in any parameter, but I just want the Records to be returned back from the procedure into a result set -> a suitable variable.
I have been trying to use the following syntax :
create or replace PROCEDURE Getmarketdetails2(data OUT varchar2)
IS
BEGIN
SELECT *
into data
from dual;
END Getmarketdetails2;
But it gives me an error while I try to execute with the following exec statement -->
Declare a Varchar2;
exec Getmarketdetails2(a);
Error: PLS-00103: Encountered the symbol "end-of-file" when expecting "something else".
Cause: Usually a PL/SQL compilation error.
Appreciate if anyone can help me out of this long pending situation! I have tried enough to find a basic guide to create a simple Oracle stored procedure and execute it in SQL Developer, but none of them answer to the point!!
You want:
DECLARE
a VARCHAR2(4000); -- Give it a size
BEGIN -- Begin the anonymous PL/SQL block
Getmarketdetails2(a); -- Call the procedure
DBMS_OUTPUT.PUT_LINE( a ); -- Output the value
END; -- End the anonymous PL/SQL block
/ -- End the PL/SQL statement
or:
VARIABLE a VARCHAR2(4000); -- Create a bind variable
EXEC Getmarketdetails2(:a); -- Execute the procedure using the bind variable
PRINT a -- Print the bind variable
Assuming an up-to-date Oracle version, you can use dbms_sql.return_result()
create or replace PROCEDURE Getmarketdetails2
IS
c1 SYS_REFCURSOR;
BEGIN
OPEN c1 FOR
SELECT *
from dual;
DBMS_SQL.RETURN_RESULT(c1);
END Getmarketdetails2;
/
Then simply run
exec Getmarketdetails2
The only drawback is that SQL Developer only displays the result as text, not as a proper result grid.
This is how I return a cursor in Oracle
PROCEDURE GetAllData (P_CURSOR OUT SYS_REFCURSOR)
IS
BEGIN
OPEN P_CURSOR FOR
SELECT *
FROM TABLE ;
END GetAllData ;
Declare a Varchar2;
exec Getmarketdetails2(a);
Your procedure is ok;
Instead of above query, use below query to run sp:
Declare
a Varchar2(10);
Begin
Getmarketdetails2(a);
End;

How to execute one procedure within another procedure

Hi I am writing one procedure which will be called by the program and this procedure will further call to another procedure to perform different business logic. so I did something like this.
PROCEDURE calculator(service_id IN NUMBER, amount IN NUMBER) as
p_proc_name varchar(100);
begin
select sc.procedure_name into p_proc_name from test.procedure sc where sc.service_config_id = service_id;
begin
execute immediate (p_proc_name) using 1;
exception when NO_DATA_FOUND then
DBMS_OUTPUT.PUT_LINE('p_proc_name = ' || p_proc_name);
end;
end sb_referal_calculator;
PROCEDURE f_service(amount IN NUMBER) as
cmpany_id NUMBER;
service_date date;
leases_days NUMBER;
referal_amount Number;
requested_quote_id number :=1;
begin
referal_amount :=0;
DBMS_OUTPUT.PUT_LINE('service_date = ');
end f_service;
PROCEDURE d_service(amount IN NUMBER) as
cmpany_id NUMBER;
service_date date;
leases_days NUMBER;
referal_amount Number;
requested_quote_id number :=1;
begin
referal_amount :=0;
DBMS_OUTPUT.PUT_LINE('service_date = ');
end d_service;
So here calcultor procedure will find the another procedure name dynamically and try to execute it with parameter. But it gives an error.
It is just a test program.
Executing PL/SQL: CALL DBMS_DEBUG_JDWP.CONNECT_TCP( '10.1.26.70', '55891' )
Debugger accepted connection from database on port 55891.
ORA-00900: invalid SQL statement
ORA-06512: at "test.demo_pkg", line 38
ORA-06512: at line 8
Executing PL/SQL: CALL DBMS_DEBUG_JDWP.DISCONNECT()
Process exited.
I really do not how this procedure will work to perform this task. I remembered it was running and I was doing testing. But really do not what i have did and stop working.
Please correct me what i doing wrong.
Thanks
When you use execute immediate it runs the dynamic statement in an SQL context that isn't able to see your PL/SQL context. That has several impacts here. Firstly, you have to call your procedure from PL/SQL so you need to create an anonymous block, as Egor Skriptunoff said, and exactly the format you need depends on what the table (and thus your vaiable) contains. The shortest it might be is:
execute immdiate 'begin ' || p_proc_name || ' end;' using 1;
But that assumes the varible contains a value like:
test_pkg.d_service(:arg);
If it only contains the name of the procedure with no arguments and no package qualifier, i.e. just d_service, it might need to be as much as:
execute immdiate 'begin test_pkg.' || p_proc_name || '(:arg); end;' using 1;
Or something in between.
The other impact is that the procedure name has to be public as it is effectively being called from outside the package when it's invoked dynamically; so it has to be declared in the package specification. That may already be the case here from the order the procedures are appearing in the body.
But if you are always calling procedures in the same package, and since you must then have a limited number of possible values, it might be simpler to avoid dynamic SQL and use the value to decide which procedure to call:
case p_proc_name
when 'f_service' then
f_service(1);
when 'd_service' then
d_service(1);
-- etc.
end case;
That also lets you call private procedures.

Unable to execute oracle procedure in PLSQL Developer

I am having sample Procedure as Below
CREATE OR REPLACE PROCEDURE proc_Table1
BEGIN
SELECT 'Sample UserName' AS UserName
FROM Dual;
END;
Now I want to run this Proc in PLSQL developer.I tried the below but its generating error
begin
proc_Table1;
end;
Its Displaying
Thanks for the Help.
Any Idea why this Happens.
When you created the procedure, you should have been alerted to the fact that you had syntax errors. If you're going to run a SELECT statement, you need to do something with the results-- either populate a local variable or open a cursor or something else. The code you've posted is also missing the IS/AS keyword
CREATE OR REPLACE PROCEDURE proc_Table1
AS
l_username VARCHAR2(30);
BEGIN
SELECT 'Sample UserName' AS UserName
INTO l_username
FROM Dual;
END;
will be syntactically valid. It doesn't appear, however, to be particularly useful-- you procedure isn't modifying the database and has no way to communicate with the caller so it isn't doing anything meaningful. As a general principal, you would also generally want to use a simple PL/SQL assignment operator to populate a local variable rather than selecting from dual, i.e.
l_username := 'Sample UserName';
Try this, it should work:
CREATE OR REPLACE PROCEDURE proc_Table1(UserName OUT VARCHAR2)
AS
BEGIN
SELECT 'Sample UserName' INTO UserName
FROM Dual;
dbms_output.put_line(UserName);
END PROC_TABLE1;
-------------------------------
How to Execute
-------------------------------
declare
name varchar2(50);
result varchar2(100);
begin
proc_table1(name);
end;

How to redirect the output of DBMS_OUTPUT.PUT_LINE to a file?

I need to debug in pl/sql to figure times of procedures, I want to use:
SELECT systimestamp FROM dual INTO time_db;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
but I don't understand where the output goes to and how can I redirect it to a log file that will contain all the data I want to collect?
DBMS_OUTPUT is not the best tool to debug, since most environments don't use it natively. If you want to capture the output of DBMS_OUTPUT however, you would simply use the DBMS_OUTPUT.get_line procedure.
Here is a small example:
SQL> create directory tmp as '/tmp/';
Directory created
SQL> CREATE OR REPLACE PROCEDURE write_log AS
2 l_line VARCHAR2(255);
3 l_done NUMBER;
4 l_file utl_file.file_type;
5 BEGIN
6 l_file := utl_file.fopen('TMP', 'foo.log', 'A');
7 LOOP
8 EXIT WHEN l_done = 1;
9 dbms_output.get_line(l_line, l_done);
10 utl_file.put_line(l_file, l_line);
11 END LOOP;
12 utl_file.fflush(l_file);
13 utl_file.fclose(l_file);
14 END write_log;
15 /
Procedure created
SQL> BEGIN
2 dbms_output.enable(100000);
3 -- write something to DBMS_OUTPUT
4 dbms_output.put_line('this is a test');
5 -- write the content of the buffer to a file
6 write_log;
7 END;
8 /
PL/SQL procedure successfully completed
SQL> host cat /tmp/foo.log
this is a test
As an alternative to writing to a file, how about writing to a table? Instead of calling DBMS_OUTPUT.PUT_LINE you could call your own DEBUG.OUTPUT procedure something like:
procedure output (p_text varchar2) is
pragma autonomous_transaction;
begin
if g_debugging then
insert into debug_messages (username, datetime, text)
values (user, sysdate, p_text);
commit;
end if;
end;
The use of an autonomous transaction allows you to retain debug messages produced from transactions that get rolled back (e.g. after an exception is raised), as would happen if you were using a file.
The g_debugging boolean variable is a package variable that can be defaulted to false and set to true when debug output is required.
Of course, you need to manage that table so that it doesn't grow forever! One way would be a job that runs nightly/weekly and deletes any debug messages that are "old".
use
set serveroutput on;
for example:
set serveroutput on;
DECLARE
x NUMBER;
BEGIN
x := 72600;
dbms_output.put_line('The variable X = '); dbms_output.put_line(x);
END;
If you are just testing your PL/SQL in SQL Plus you can direct it to a file like this:
spool output.txt
set serveroutput on
begin
SELECT systimestamp FROM dual INTO time_db;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);
end;
/
spool off
IDEs like Toad and SQL Developer can capture the output in other ways, but I'm not familiar with how.
In addition to Tony's answer, if you are looking to find out where your PL/SQL program is spending it's time, it is also worth checking out this part of the Oracle PL/SQL documentation.
Using UTL_FILE instead of DBMS_OUTPUT will redirect output to a file:
http://oreilly.com/catalog/oraclebip/chapter/ch06.html
As a side note, remember that all this output is generated in the server side.
Using DBMS_OUTPUT, the text is generated in the server while it executes your query and stored in a buffer. It is then redirected to your client app when the server finishes the query data retrieval. That is, you only get this info when the query ends.
With UTL_FILE all the information logged will be stored in a file in the server. When the execution finishes you will have to navigate to this file to get the information.
Hope this helps.
Its possible write a file directly to the DB server that hosts your database, and that will change all along with the execution of your PL/SQL program.
This uses the Oracle directory TMP_DIR; you have to declare it, and create the below procedure:
CREATE OR REPLACE PROCEDURE write_log(p_log varchar2)
-- file mode; thisrequires
--- CREATE OR REPLACE DIRECTORY TMP_DIR as '/directory/where/oracle/can/write/on/DB_server/';
AS
l_file utl_file.file_type;
BEGIN
l_file := utl_file.fopen('TMP_DIR', 'my_output.log', 'A');
utl_file.put_line(l_file, p_log);
utl_file.fflush(l_file);
utl_file.fclose(l_file);
END write_log;
/
Here is how to use it:
1) Launch this from your SQL*PLUS client:
BEGIN
write_log('this is a test');
for i in 1..100 loop
DBMS_LOCK.sleep(1);
write_log('iter=' || i);
end loop;
write_log('test complete');
END;
/
2) on the database server, open a shell and
tail -f -n500 /directory/where/oracle/can/write/on/DB_server/my_output.log
An old thread, but there is another alternative.
Since 9i you can use pipelined table function.
First, create a type as a table of varchar:
CREATE TYPE t_string_max IS TABLE OF VARCHAR2(32767);
Second, wrap your code in a pipelined function declaration:
CREATE FUNCTION fn_foo (bar VARCHAR2) -- your params
RETURN t_string_max PIPELINED IS
-- your vars
BEGIN
-- your code
END;
/
Replace all DBMS_OUTPUT.PUT_LINE for PIPE ROW.
Finally, call it like this:
SELECT * FROM TABLE(fn_foo('param'));
Hope it helps.
Try This:
SELECT systimestamp INTO time_db FROM dual ;
DBMS_OUTPUT.PUT_LINE('time before procedure ' || time_db);

Resources