PLSQL oracle select after declare ORA-06550 PLS-00103 - sql

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;

Related

How to check if row exists before SELECT INTO statement in Oracle SQL

I'm using Oracle SQL and have a procedure that is doing some operations on tables. During the procedure there is a "SELECT x INTO y FROM TABLE z WHERE..." statement inside a loop. Unfortunatly during the procedure I can't guarante that there is always a row to the corresponding where condition because it changes dynamically.
Is it possible to check if a row exists before the statement? I was thinking of sth like "if exists(select ...) then SELECT X INTO y..."
Thanks for the help!
Jack
Well, there's no point in checking it first, and re-using the same statement again.
You could handle the exception (possibly in an inner BEGIN-EXCEPTION-END block):
declare
y number;
begin
begin --> inner block starts here
select x into y from z where ...
insert into ...
exception
-- handle it, somehow; I chose not to do anything
when no_data_found then
null;
end; --> inner block ends here
end;
Or, if you used cursor FOR loop, you wouldn't have to handle it because - if select returns x, insert would run. Otherwise, nothing in that loop would ever be executed:
begin
for cur_r in (select x from z where ...) loop
insert into ...
end loop;
end;
An exception handler as in Littlefoot's answer is the most correct and explicit approach, however just for completeness you might also consider using an aggregate.
Value 'X' exists in the table:
declare
p_someparam varchar2(1) := 'X';
l_somevalue varchar2(1);
l_check number;
begin
select max(dummy), count(*) into l_somevalue, l_check
from dual d
where d.dummy = p_someparam;
dbms_output.put_line('Result: '||l_somevalue);
dbms_output.put_line(l_check||' row(s) found');
end;
Result: X
1 row(s) found
Value 'Z' does not exist in the table:
declare
p_someparam varchar2(1) := 'Z';
l_somevalue varchar2(1);
l_check number;
begin
select max(dummy), count(*) into l_somevalue, l_check
from dual d
where d.dummy = p_someparam;
dbms_output.put_line('Result: '||l_somevalue);
dbms_output.put_line(l_check||' row(s) found');
end;
Result:
0 row(s) found
You can add logic to handle the cases where the count check is 0 or greater than 1.
If you are having procedure then I should say use if statement and then write the sql:
select some_column into some_variable from tablename where condition
IF somevariable not in (<list of values separated by comma>)THEN
{statements to execute }
END IF;

Declaring cursor in a PL/SQL stored procedure

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;

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;
/

variable as column name in where clause in Oracle PL/SQL

I am working on PL/SQL code where I need to perform a select query using variable as column name in where clause. Column names are stored in a table as varchar and I am using a loop to pass those column names to my select statement.
Please find sample code segment I am trying to run:
set serveroutput on;
declare
var varchar2(100);
counter number;
begin
var:='description';
select count(*)
into counter
from nodetable
where var like '%Ship%';
dbms_output.put_line(counter);
end;
Output:
anonymous block completed
0
However the result should be 86.
Oracle is comparing last condition as two string and not column=string.
Please let me know if this is even feasible in oracle or if there is a workaround for it.
Regards
Ankit
You have to use dynamic SQL, preferrably with bind-variables:
EXECUTE IMMEDIATE
'select count(*) from nodetable where '||var||' like :p1'
INTO counter
USING '%Ship%';
Try this
declare
var varchar2(100);
counter number;
begin
var:='description';
EXECUTE IMMEDIATE
'select count(*)
into counter
from nodetable
where '||var||' like ''%Ship%'' ';
dbms_output.put_line(counter);
end;
You need to be carefull with the colon's (').
I agreed with previous answer in implementation, but i strictly recommend you to change your technical requirements, because you can't use bind variables for this, and it's potential place for injection. For example, if someone will edit value in your table which stores column names, to something like that: "description = inject_function or description". Then your dynamic sql block will execute this statement:
select count(*) from nodetable where description = inject_function or description like '%Ship%
and example implementation of function
create function inject_function
return varchar2
is pragma autonomous_transaction;
begin
delete * from most_important_table;
commit;
return to_char(null);
exception when others then
rollback;
return to_char(null);
end;

trouble defining weakly defined ref cursor

I'm attempting to write a stored proc that takes in a number, n, and returns the first n results for a given query, exclusively locking those n rows. I'm a little new to SQL and I'm having a bit of difficulty matching data types correctly.
My package spec looks like this:
PACKAGE package IS
Type out_result_type is REF CURSOR;
PROCEDURE stored_proc
(in_n IN NUMBER DEFAULT 10,
out_list IN OUT out_result_type);
I then define the cursor in the procedure body, like so:
CURSOR OUT_RESULT_TYPE IS
SELECT a.id
FROM schema.table a
WHERE (some conditions) AND rownum <= in_n;
A bit later on I then try to extract the results of the cursor into the output variable:
OPEN OUT_RESULT_TYPE;
FETCH OUT_RESULT_TYPE INTO out_list; -- error on this line
CLOSE OUT_RESULT_TYPE;
But alas this code doesn't compile; oracle complains that out_list has already been defined with a conflicting data type. Any idea how I can resolve this issue? It's driving me crazy!
Thanks in advance.
CREATE OR REPLACE PACKAGE pkg_test
AS
TYPE tt_cur IS REF CURSOR;
PROCEDURE prc_cur (retval OUT tt_cur);
END;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT *
FROM dual;
END;
END;
If you want to lock, use:
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur (retval OUT tt_cur)
AS
BEGIN
OPEN retval
FOR
SELECT a.id
FROM schema.table a
WHERE (some conditions)
AND rownum <= in_n
ORDER BY
column
-- Never forget ORDER BY!
FOR UPDATE;
END;
END;
Two remarks:
A cursor doesn't lock.
You don't have to do Type out_result_type is REF CURSOR;, use default type sys_refcursor. See here: Oracle - How to have an out ref cursor parameter in a stored procedure?
Your out_list must be of wrong type. Consider (script run on 10.2.0.3):
CREATE TABLE t AS SELECT ROWNUM ID FROM all_objects WHERE ROWNUM <= 100;
CREATE OR REPLACE PACKAGE cursor_pck AS
TYPE out_result_type is REF CURSOR;
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type);
END cursor_pck;
/
If you want to select and lock the rows at the same time you would use the FOR UPDATE clause:
CREATE OR REPLACE PACKAGE BODY cursor_pck AS
PROCEDURE stored_proc (p_in IN NUMBER DEFAULT 10,
p_out_list IN OUT out_result_type) IS
BEGIN
OPEN p_out_list FOR SELECT a.id FROM t a WHERE ROWNUM <= p_in FOR UPDATE;
END stored_proc;
END cursor_pck;
/
With the following setup, you will call the procedure like this:
SQL> SET SERVEROUTPUT ON;
SQL> DECLARE
2 l_cursor cursor_pck.out_result_type;
3 l_id t.id%TYPE;
4 BEGIN
5 cursor_pck.stored_proc(3, l_cursor);
6 LOOP
7 FETCH l_cursor INTO l_id;
8 EXIT WHEN l_cursor%NOTFOUND;
9 dbms_output.put_line(l_id);
10 END LOOP;
11 END;
12 /
1
2
3
PL/SQL procedure successfully completed
This is not going to work the way it's written, because
out_list expects a cursor, not a cursor result.
The name out_result_type is already used for a type, so you can't redefine it to be a cursor in the same scope.
Oracle provides a pre-defined weak reference cursor: sys_refcursor. In usage it would look like:
CREATE OR REPLACE PACKAGE pkg_test
AS
PROCEDURE prc_cur (p_retval OUT sys_refcursor,
p_lookup IN VARCHAR2);
END pkg_test;
CREATE OR REPLACE PACKAGE BODY pkg_test
AS
PROCEDURE prc_cur(p_retval OUT sys_refcursor
p_lookup IN VARCHAR2)
IS
BEGIN
OPEN retval FOR SELECT a.value
FROM tblname a
WHERE a.id <= p_lookup;
END prc_cur;
END pkg_test;
This saves you the trouble of needing to declare a type. The sys_refcursor is a pointer to a result set from an open cursor. If you are familiar with Java, it's the same concept as the java.sql.ResultSet object which provides a way to get at the results of a query.