Declaring cursor in a PL/SQL stored procedure - sql

printf('local_time_greeting');
Having some trouble getting a stored procedure to run with SQL Developer. Below is an example patterned exactly like the first few lines, with variable names changed for security reasons.
CREATE OR REPLACE PROCEDURE redacted ( an_in_variable IN VARCHAR ) AS
these VARCHAR;
variables VARCHAR;
don_apostrophe_t INT;
matter INT;
BEGIN
DECLARE cursor_giving_me_trouble CURSOR FOR
SELECT something FROM db.table WHERE condition_1 = condition_2;
...
In the editor the SELECT word is red-wavy-lined, and when I try to run the code the output returns
PLS-00103: Encountered symbol "FOR" when expecting one of the following := . ( # % ; not null range default character
Any ideas?

You need to use IS rather than FOR, but you have the terms of the definition in the wrong order as well:
DECLARE
CURSOR cursor_giving_me_trouble IS
SELECT something FROM db.table WHERE condition_1 = condition_2;
db<>fiddle which still errors because of the illegal object names in your obfuscated code, but not from the syntax; and a more complete example.
It's also possible you're trying to use the construct:
FOR cursor_giving_me_trouble IN (
SELECT something FROM db.table WHERE condition_1 = condition_2
) LOOP
...
rather than a sub-block (a new declare, followed by begin/end) with references only to cursor within that. db<>fiddle.

To get you started:
create or replace procedure redacted
( an_in_variable in varchar2 )
as
these varchar2(123);
variables varchar2(456);
don_apostrophe_t integer;
matter integer;
cursor cursor_giving_me_trouble is
select 'Welcome to PL/SQL' as whatever from dual where 1=1;
begin
for r in cursor_giving_me_trouble loop
dbms_output.put_line(r.whatever);
end loop;
end;
However, you often don't need a separate cursor definition as there is this compact syntax:
create or replace procedure redacted
( an_in_variable in varchar2 )
as
these varchar2(123);
variables varchar2(456);
don_apostrophe_t integer;
matter integer;
begin
for r in (
select 'Welcome to PL/SQL' as whatever from dual where 1=1
)
loop
dbms_output.put_line(r.whatever);
end loop;
end;

Related

PL/SQL equivalent of SELECT statement

What would be the PL/SQL equivalent of this SQL query:
SELECT * FROM table(OWNER.PACKAGE.get_exam('123456789'));
This is the Function that I am trying to call:
FUNCTION get_exam(id IN VARCHAR2)
RETURN ab_assign_v1
IS
CURSOR c_exams(cid VARCHAR2) IS
SELECT t_api_exam_v1(
sei.person_id, --unique id
l.description --loc description
)
FROM my_view sei
JOIN loc l
ON sei.loc_code = l.loc_code
v_collection ab_assign_v1;
BEGIN
OPEN c_exams(id);
FETCH c_exams BULK COLLECT INTO v_collection;
CLOSE c_exams;
RETURN v_collection;
EXCEPTION
WHEN OTHERS THEN
error_a1.raise_error(SQLCODE, SQLERRM);
END get_exam;
Hope this helps.
DECLARE
lv <COLLECTION_NAME>;
BEGIN
lv:= OWNER.PACKAGE.get_exam('123456789');
dbms_output.put_line(lv.COUNT);
END;
/
Assuming that you want to return the result of a function :
select owner.package.get_exam('123456789') from table
Your function returns a nested table type. You simply need to declare a variable of that type, and assign to it as you would if it were a scalar:
declare
l_coll your_collection_type;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/
In this example your_collection_type is a placeholder for whatever object your function actually returns.
" I am getting this error: PLS-00201: identifier 'ab_assign_v1' must be declared "
ab_assign_v1 is the type used by your function. From the code posted in your revised question it seems that type is in the same schema which owns the package with the function. However your original pseudo-code prefixes the call with the schema name. So, putting two and two together, you need to revise the variable declaration to include the schema too. (You may need to grant EXECUTE on it too, if you haven't done this already).
declare
l_coll OWNER.ab_assign_v1;
begin
l_coll := OWNER.PACKAGE.get_exam('123456789');
end;
/

PLSQL oracle select after declare ORA-06550 PLS-00103

Using PL/SQL Developer client.
Oracle throws me ORA-065550 PLS-00103 Encountered the symbol "SELECT".
Well, can not find what's wrong here.
DECLARE someId NUMBER;
BEGIN
select id into someId from someTable where someColumn = 'someUniqueValue';
select * from someTable; --here
END;
select * from someTable; --or here
Neither second select, neither third works. When I dmbs_output someId into console it works well, this assigning to declared variable. But why I can not just select after 'into'? I want to declare one time value, and then make
select * from someTable where id = someId
or to be precised want to make like thousand inserts and I want to cache that first select.
DECLARE someId NUMBER;
BEGIN
select id into someId from someTable where someColumn = 'someValue';
END;
/
select * from otherTable where otherTableId = someId;
Here I lost someId scope I guess.
Basically you doing a lot of mistakes while doing this code.
1.You cant just 'SELECT *' in the anonymous block. You need to have cursor to do it.
2.Your variable scope is till the anonymous block. Now you are trying to access the variable outside the block --> NAAH not possible.
So I have tried to resolve your issue by below snippet hope it helps.
DECLARE
someId NUMBER;
p_lst sys_refcursor;
BEGIN
SELECT id INTO someId FROM someTable WHERE someColumn = 'someUniqueValue';
OPEN p_lst FOR
'SELECT * FROM someTable
where otherTableId = '||someId;
END;
Assuming you're coding a sql script, you can
1) declare your variable
2) populate it in an anonymous pl/sql block
3) use it elsewhere
--1
variable my_num number
--2
begin
select 1 into :my_num from dual;
end;
/
--3
select :my_num from dual;
That you can achieve through using SQL*Plus
SQL> variable id number
SQL> begin
select 1000 into :id from dual;
end;
/
SQL> print id
ID
----------
1000
SQL> SELECT * FROM tbl_a WHERE id = :id
In Oracle doesn't let you implicitly return the result of a query. The result always has to be explicitly returned in some fashion. The simplest way is to use DBMS_OUTPUT (roughly equivalent to print) to output the variable:
DECLARE
myname varchar2(20);
BEGIN
myname := 'Tom';
dbms_output.print_line(myname);
END;
This isn't terribly helpful if you're trying to return a result set, however. In that case, you'll either want to return a collection or a refcursor. However, using either of those solutions would require wrapping your code in a function or procedure and running the function/procedure from something that's capable of consuming the results. A function that worked in this way might look something like this:
CREATE FUNCTION my_function (myname in varchar2)
my_refcursor out sys_refcursor
BEGIN
open my_refcursor for
SELECT *
FROM Customers
WHERE Name = myname;
return my_refcursor;
END my_function;

PL/SQL query with parameter

I am familiar with MSSQL and using a parameter within the query, but I am not sure how I would do this within PL/SQL.
DECLARE
LSITEID NUMBER := 100001;
BEGIN
SELECT * from invoicehead ih
JOIN sitemaster sm on sm.SITEIID = ih.SITEIID
JOIN invoiceline il on il.invoiceIID = ih.invoiceIID
WHERE
ih.StartDate BETWEEN '2015-12-01' AND '2016-03-07'
AND SITEIID IN ( LSITEID)
END;
Right now I am testing this within Pl/SQL. But essentially I would be passing in the query with the parameter from MSSQL Linked Server OPENQuery.
How I can run the above query in PL/SQL with the parameter?
There is plenty of other resource for finding an answer, e.g. here (Tutorialspoint) or specifically here (plsql-tutorial). But perhaps I have missed your point.
To not remain on merely citing links, your query could look like this:
DECLARE
LSITEID integer;
BEGIN
LSITEID := 100001;
-- dostuff
END;
Two things to note: First, in a declare part (as I have learnt it) you should avoid assigning values. Second, if you intend to pass in different parameters you could/should use a procedure.
In PL/SQL you just use the name of the argument. In the following example, the argument is P_VALUE, note select statement says where dummy = p_value.
DECLARE
FUNCTION dummycount (p_value IN DUAL.dummy%TYPE)
RETURN INTEGER
AS
l_ret INTEGER;
BEGIN
SELECT COUNT (*) c
INTO l_ret
FROM DUAL
WHERE dummy = p_value;
RETURN l_ret;
END dummycount;
BEGIN
DBMS_OUTPUT.put_line ('A: ' || dummycount (p_value => 'A'));
DBMS_OUTPUT.put_line ('X: ' || dummycount (p_value => 'X'));
END;
This results in the following output:
A: 0
X: 1

What is this doing? Listing variables without declaring them?

This is my code:
--this section creates/replaces the C_PND Procedure
--and passes 2variables
create or replace PROCEDURE C_PND
(
p_whse in varchar2,
p_RC OUT INT
)
--No clue what we're doing here as there is no DECLARE
as
cv SYS_REFCURSOR; -- cursor variable
v_pull_zone locn_hdr.pull_zone%TYPE;
v_active varchar2(1);
v_low_wm number(3);
v_high_wm number(3);
v_lock_code resv_locn_hdr.locn_putaway_lock%TYPE;
--initializes this variable
BEGIN
p_RC := 0;
--setting values of the the CV
OPEN cv FOR
select code_id,
nvl(trim(substr(sc.misc_flags,1,1)),'N') v_active,
nvl(trim(substr(sc.misc_flags,2,3)),'100') high_wm,
nvl(trim(substr(sc.misc_flags,5,3)),'0') low_wm,
trim(substr(sc.misc_flags,8,2)) lock_code
from sys_code sc
where sc.rec_type = 'C'
and sc.code_type = 'PND';
--inputting the CV into these variables
LOOP
FETCH cv INTO v_pull_zone, v_active, v_high_wm, v_low_wm, v_lock_code;
EXIT WHEN cv%NOTFOUND;
............
............
............
I think I understand most of it but my problem comes in with the five lines after the as (lines 6-11 of code snippet). I'm under the impression that anytime you use variables in PL SQL you have to DECLARE them. Even if you are using cursor variables.
Am I simply wrong about that? Or is there no need to DECLARE variables in use with CVs? I also included some comments (prefaced by --) that show what I think what the SQL is doing.
You are sort of right. You have to declare variables using DECLARE in an anonymous block as in:
DECLARE
...
BEGIN
...
END;
Your code is a procedure and the DECLARE is implicit after the
CREATE OR REPLACE xxx as
(implicit DECLARE)
BEGIN
...
END;

How to populate variable in pl sql on declaration in store procedure with sql statement return

So I have a variable on the declaration on the store procedure. It must have a default value that is populated on the return of a sql statement. The thing is that that variable is used in the declaration of the query of a cursor, thats why it needs to be populated on the declaration. How am i supposed to do this?
create or replace
PROCEDURE PROCESAR AS
ultimaejecucion date := select fecha from table where rownum<=1;
--I know I have to use the word INTO but throws me error when i compile.
cursor cursor_licencias is
select lic.campo1
from lic lic
where lic.licfhing >= ultimaejecucion
BEGIN
open cursor
.
.
.
END PROCESAR;
Your problem is quite unclear. If your cursor always depends on values from another table, you should include this table to query, as Multisync advised. If your cursor also has to depend on different rows of that table, you can use cursor parameters to choose that row:
create or replace
PROCEDURE PROCESAR AS
cursor cursor_licencias (cursor_parameter number default 1234) is
select lic.campo1
from lic lic
where lic.licfhing >= (select fecha from table where column = cursor_parameter);
BEGIN
open cursor cursor_licencias; -- using with default value
open cursor cursor_licencias (5678); -- using with value '5678'
END PROCESAR;
Example in oracle documentation.
You may move it into the cursor declaration:
create or replace
PROCEDURE PROCESAR AS
cursor cursor_licencias is
select lic.campo1
from lic lic
where lic.licfhing >= (select fecha from table where rownum<=1);
BEGIN
open cursor
.
.
.
END PROCESAR;
if you need this field somewhere else you can assign the value to the ultimaejecucion right after BEGIN
I would do something like:
declare
l_date date;
-- the value of l_date does not matter at this point
cursor sel_cur is
select 'It works' as val
from dual
where sysdate > l_date;
begin
-- populate l_date using query
select sysdate - 1
into l_date
from dual;
-- open cursor (implicitly).
-- here the value of l_date is used in the execution of the query
for rec in sel_cur
loop
dbms_output.put_line(rec.val);
end loop;
end;