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;
Related
Apologies for the newbie question, I am writing an Oracle stored procedure that opens a cursor for a specific SQL, calculates some variables for each row returned by the cursor but the stored procedure should return as a result set these variables that have been calculated for each row returned by the cursor. I am a bit confused on how to do this - can anyone help?!
I did read some of it so far I have something like this (just a trimmed down example and not exact code) but just need to return v_calc and v_calc_res in a result set:-
CREATE OR REPLACE procedure sp_test
(
in_input in number,
out_return out sys_refcursor
)
as
v_calc number;
v_calc_res number;
CURSOR C_test IS
select blah from test where blah = in_input;
begin
open c_test
loop
fetch c_test into v_calc;
v_calc_res := v_calc*5;
end loop;
end;
If you want a procedure to return a reference cursor for the calling routine to consume the procedure itself cannot then consume it. Cursors, including reference cursors are 1 way, 1 time consumables. As for as the desired calculations, they can be added to select defined for the cursor. So:
-- setup
create table test (blah integer, blah_stuff varchar2(50) );
-- build sp
create or replace procedure sp_blah_text(
in_input in number
, out_cur out sys_refcursor
)
is
begin
open out_cur for
select blah, blah_stuff, blah*5 as blah_x_5
from test
where blah = in_input;
end sp_blah_text;
-- test data
insert into test(blah, blah_stuff)
select 1,'a' from dual union all
select 2,'b' from dual union all
select 2,'x' from dual union all
select 2,'z' from dual union all
select 3,'c' from dual;
-- test
declare
ref_cur sys_refcursor;
l_blah test.blah%type;
l_stuff test.blah_stuff%type;
l_blah_5 test.blah%type;
begin
dbms_output.enable(null);
sp_blah_text(2,ref_cur);
loop
fetch ref_cur
into l_blah
, l_stuff
, l_blah_5;
exit when ref_cur%notfound;
dbms_output.put_line('blah=' || l_blah || ',stuff=' || l_stuff || ',blah*5=' || l_blah_5);
end loop;
end;
This works a treat thank you very much. I now have a performance issue that maybe you could help with. When I open the cursor, I then run several other SELECT statements to retrieve values using the variables from the cursor (see below). I assume this is because the switch between PL/SQL and SQL engine. Would using table collections help? But as I see since I need different columns from different tables I would need to have several different collections, how could I output everything in one record?
CREATE OR REPLACE procedure sp_test
(
in_input in number
)
as
v_calc number;
v_calc_res number;
v_blah_blah number;
v_blah_blah_blah number;
v_blah_blah_blah number;
CURSOR C_test IS
select blah from test where blah = in_input;
begin
open c_test
loop
fetch c_test into v_calc;
select blah_blah into v_blah_blah from t_blah_blah;
select blah_blah_blah into v_blah_blah_blah from t_blah_blah_blah;
select blah_blah_blah_blah into v_blah_blah_blah_blah from t_blah_blah_blah_blah;
v_calc_res := v_calc*5*v_blah_blah*v_blah_blah_blah*v_blah_blah_blah_blah
end loop;
end;
I am trying to return the data through refcursor that is used in Select for update but I am not able to find any way. Can any one please guide me.
CREATE OR REPLACE PROCEDURE SELECT_SCHEDULED_REPORTS
(o_scheduledreports_cursor OUT SYS_REFCURSOR)
IS
CURSOR report_ids
IS
SELECT *
FROM dwp_rep_scheduler_t
WHERE SCHEDULE_ID IN
(SELECT SCHEDULE_ID
FROM
(SELECT *
FROM dwp_rep_scheduler_t a
WHERE status = 1
AND schedule_type = 1
ORDER BY a.start_date
)
WHERE ROWNUM <= 5
) FOR UPDATE OF status;
BEGIN
FOR report_id IN report_ids
LOOP
UPDATE dwp_rep_scheduler_t SET status = 2 WHERE CURRENT OF report_ids;
END LOOP;
COMMIT;
-- can I do something like open o_scheduledreports_cursor for report_ids
END;
/
As suggested by #Lalit Kumar B, i tried following but now it compiles with error as "PLS-00221: 'O_SCHEDULEDREPORTS_CURSOR' is not a procedure or is undefined"
CREATE OR REPLACE PROCEDURE SELECT_SCHEDULED_REPORTS (
o_scheduledreports_cursor OUT SYS_REFCURSOR)
IS
begin
open o_scheduledreports_cursor for
SELECT *
FROM dwp_rep_scheduler_t
WHERE SCHEDULE_ID IN (SELECT SCHEDULE_ID
FROM ( SELECT *
FROM dwp_rep_scheduler_t a
WHERE status = 1 AND schedule_type = 1
ORDER BY a.start_date)
WHERE ROWNUM <= 5)
FOR UPDATE OF status;
BEGIN
FOR report_id IN o_scheduledreports_cursor
LOOP
UPDATE dwp_rep_scheduler_t
SET status = 2
WHERE CURRENT OF report_ids;
END LOOP;
COMMIT;
END;
END SELECT_SCHEDULED_REPORTS;
/
Select for update is a programming tool which you would use to ensure that no one else updates your data. Inside you PL/SQL, you would use the rows locked for update, and then do the required transaction. Commit your changes, Oracle would release the lock mode 3.
You could simply do,
Open cur for
select column_list from table where ....
Not that specific, but, this asktom link about select for ...update is a good read https://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:927629362932
You might also be interested to know few interesting things about the clause, here is my take on a myth about select..for update http://lalitkumarb.wordpress.com/2014/09/04/a-myth-about-row-exclusive-table-lock-on-select-for-update-with-no-rows/
Hope it helps!
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;
I can't seem to get variables to work in an Oracle PL/SQL where clause. I come from a Microsoft SQL Server background and there it was easy. For example, what would be all steps needed to do something similar to the following?
declare #var int set #var = 1
select * from SomeTable where SomeField = #var
This doesn't seem like it should be hard in PL/SQL, but evidently it is. :-/ I hear I need to use cursors and the like in PL/SQL?
Any help would be greatly appreciated. Thanks.
What do you want to do with the data that the SELECT returns? If you just want to see it you don't need PL/SQL at all, just do this in SQL Plus:
variable var number
exec :var := 1
select * from SomeTable where SomeField = :var;
Or in a tool like SQL Developer or Toad, just do this:
select * from SomeTable where SomeField = :var;
and it will prompt you to enter the value for :var.
The following code declares a variable var to use in the WHERE clause, and a variable result to put the result in then executes it inside a PL/SQL block.
DECLARE
var INT := 1;
result INT;
BEGIN
SELECT 123
INTO result
FROM DUAL
WHERE var = 1;
DBMS_OUTPUT.put_line (var);
DBMS_OUTPUT.put_line (result);
END;
The DBMS_OUTPUT.PUT_LINE calls make it produce this DBMS output:
1
123
declare
type t_rec is record
(
col1 number,
col2 myTable.col2%type
);
v_rec t_rec;
type t_tab is table of v_rec%type index by binary_integer;
v_tab t_tab;
begin
select col1, col2
bulk collect into v_tab
from myTable
where col3 = 'BLAH';
-- do something great with v_tab...
end;
Also know that if you try to select into (or bulk collect into) a variable and no rows are returned, you'll get a no_data_found exception, so you may want to handle that situation.
See more here on pl/sql collections. Above uses an associative array, but there are nested tables and varrays as well. Again, see the link.
Hope that helps.
I use it like this
select * from sec_mainmenu where serno = '&MENU_ID';
When you run it, pl/sql will prompt for MENU_ID value.
I have written the following query to get the last executed SQL statement in the oracle database for a particular session. The SQL text does not contain the actual value of the bind variables. How to get the bind variable values along with the SQL text.
SELECT * FROM v$SQLTEXT_WITH_NEWLINES WHERE address =
(SELECT prev_sql_addr FROM v$session WHERE audsid = userenv('SESSIONID'))
ORDER BY piece;
To get the bind variables you will have to use the code below, you dont need to use tracing.
SELECT * FROM v$sql_bind_capture WHERE sql_id='';
or
SELECT NAME,POSITION,DATATYPE_STRING,VALUE_STRING
FROM v$sql_bind_capture WHERE sql_id='';
http://shaharear.blogspot.com/2009/02/find-bind-variable-value.html
I don't think the bind variables values are stored by default. Not considering the potential security problems (seeing other sessions actual work), the amount of data to store would be massive.
If you want to see the values of the bind variables, you should activate the trace for that session. You would do this by executing the following command in that session:
alter session set events '10046 trace name context forever, level 12';
More information on AskTom: 10046 tracing
if you are in sqlplus you can execute
select * from table
( dbms_xplan.display_cursor (null,null, 'ADVANCED'));
or if you are looking for SQL executed by someone else just put in their the SQL_ID and child cursor #:
select * from table
( dbms_xplan.display_cursor ('sql_id',child_cursor#, 'ADVANCED'));
as in
select * from table
( dbms_xplan.display_cursor ('a18asdr99x',0, 'ADVANCED'));
This method shows the only shows peeked bind variables. The only dependable way is tracing with bind variables
dbms_monitor.session_trace_enable(session_id => 127,
serial_num => 29,
waits => FALSE,
binds => TRUE)
but of course that has to be done before the query gets executed
Run the below query which takes the sql_id as the input parameter and will give the output with replaced bind variable values.
set serveroutput on;
DECLARE
v_fulltext CLOB;
v_sql_id VARCHAR2 (100);
CURSOR c1( v_sql_id varchar2)
IS
SELECT decode(substr(NAME,1,4),':SYS',replace(name,':',':"')||'"' ,NAME ) NAME, POSITION, datatype_string,nvl(VALUE_STRING,'NULL') value_string
FROM v$sql_bind_capture
WHERE sql_id = v_sql_id;
BEGIN
v_sql_id:= '&sql_id';
SELECT sql_fulltext
INTO v_fulltext
FROM v$sql
WHERE sql_id =v_sql_id AND ROWNUM = 1;
FOR rec IN c1(v_sql_id)
LOOP
IF substr(rec.datatype_string,1,8) = 'VARCHAR2'
THEN
SELECT REPLACE (v_fulltext,
rec.NAME,
'''' || rec.value_string || ''''
)
INTO v_fulltext
FROM DUAL;
END IF;
IF rec.datatype_string = 'NUMBER'
THEN
SELECT REPLACE (v_fulltext, rec.NAME, rec.value_string)
INTO v_fulltext
FROM DUAL;
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE(v_fulltext);
EXCEPTION
WHEN NO_DATA_FOUND
THEN DBMS_OUTPUT.PUT_LINE('NO SQL FOUND FOR THE SQL ID');
END;
/
Looking at BiPin's answer I modified it a bit to suit my needs.
I needed to figure out what parameters users were using when running a report in real time. Here's my solution which adds the childnumber to the query from v$sql_bind_capture.
declare
v_sql_id varchar(100);
v_fulltext clob;
v_childnumber number;
begin
v_sql_id := '&sql_id';
v_childnumber := '&childnumber';
SELECT LISTAGG(SQL_text, '') within group (order by piece)
INTO v_fulltext
FROM v$sqltext
WHERE sql_id =v_sql_id;
for I in (select name,VALUE_STRING from v$sql_bind_capture where sql_id = V_SQL_ID and child_number = V_CHILDNUMBER)LOOP
v_fulltext := regexp_replace(v_fulltext,i.name||' ',i.value_string);
end LOOP;
DBMS_OUTPUT.PUT_LINE(v_fulltext);
end;