Oracle PL/SQL SELECT INTO clause thinks it needs another INTO - oracle

I have a simple test function where I'm passing in a specific ID (the primary key of the table I'm selecting from), and computing a simple function on it and the parameters.
The skeleton code and test:
create or replace function test(id varchar2, area float) return float is
theRow forest%ROWTYPE;
begin
select * into theRow from forest where Forest_No = id;
return area / theRow.Area;
end;
begin
select test('1', 16000) from dual;
end;
The output:
[2019-10-14 21:19:10] [65000][6550] ORA-06550: line 2, column 5:
[2019-10-14 21:19:10] PLS-00428: an INTO clause is expected in this SELECT statement
I am at a loss for what to do here, as far as I can tell the documentation and examples use the same order and syntax. I have tried moving the into clause to the end as in Postgresql, but that did not work.
What have I missed here?

Issue is in calling statement.
Whenever select statement is used in plsql block it must have into clause to assign return value to variable.
You should remove begin and end from your calling code:
--begin -- remove this
select test('1', 16000) from dual;
--end; -- remove this
Or if you want to use it in plsql block then add into clause:
Declare
Area_ float(precision);
begin
select test('1', 16000) into area_ from dual;
-- use area_ in your code wherever required
dbms_output.put_line('area: ' || area_);
end;
Cheers!!

Related

Raise an error if a subquery returns no result

In DB2 it is possible to raise an error if a subquery returns no results with the help of coalesce and the raise_error scalar function. But how can this be done in oracle?
I checked scalar functions so far, but there is no raise error function.
example for db2 (note: the subquery needs to be replaced by something meaningful...):
SELECT
COALESCE(
(SELECT 1 FROM SYSIBM.SYSDUMMY1 LIMIT 0),
RAISE_ERROR('70NUL', 'Value is missing'))
FROM
SYSIBM.SYSDUMMY1;
UPDATE 1:
The use case is about finding a matching value in another table during an export of millions of records. The idea is to raise an error if there is no matching value so it is detected early and not afterwards.
The way you describe it it sounds as if you need to mark a number of records based on whenever some values exist in a table. If PLSQL is an option you can just use the no_data_found exception:
invalid_data CONSTANT NUMBER := -70;
DECLARE
l_var NUMBER;
BEGIN
SELECT 1
INTO l_var
FROM dual
WHERE 1 <> 1;
EXCEPTION WHEN no_data_found THEN
/* do your updating or error handling */ RAISE_APPLICATION_ERROR(invalid_data ,'Value is missing');
END;
You can use RAISE_APPLICATION_ERROR feature of oracle to resolve your problem. You can declare a procedure and define when to raise the exception in that procedure. Simply call the procedure to execute your task and it will raise the error whenever your given condition staisfies.
For knowing in details, please see the trapping user defined exceptions section of oracle documentation with example.
In Oracle, you'd use similar query:
SQL> select coalesce((select dummy from dual where 1 = 2), 'Value is missing') result from dual;
RESULT
----------------
Value is missing
SQL> select coalesce((select dummy from dual where 1 = 1), 'Value is missing') result from dual;
RESULT
----------------
X
SQL>
I don't speak MS SQL Server so I can't comment it.
Alternative to #Gnqz solution is to write a user function wrapper around raise_application_error() in conjunction with coalesce.
CREATE OR REPLACE FUNCTION raise_error
RETURN NUMBER
IS
BEGIN
raise_application_error(-70, 'Mapping value is missing');
RETURN(0);
END;
select coalesce((select 5 AS result from dual fetch first 1 row only), raise_error()) AS result from dual;

Oracle PL/SQL - parameterizing SAMPLE clause in SELECT statement

I have a Oracle related question. I would like to select a random sample out of a view or table in such a way that the SAMPLE clause is parameterized.
Given the following table.
CREATE TABLE FOO AS
(SELECT LEVEL AS ID
FROM DUAL
CONNECT BY LEVEL < 101
);
The following construct works, using a literal parameter in the SAMPLE clause.
SELECT ID FROM FOO SAMPLE (15); -- this will get a 15% sample
However,
DECLARE
N NUMBER := 50;
BEGIN
FOR r IN
( SELECT ID FROM FOO SAMPLE (N) -- <<< this won't work
)
LOOP
DBMS_OUTPUT.PUT_LINE( r.ID );
END LOOP;
END;
This block blows up when we put a parameter in the SAMPLE clause. It compiles and works if we put it a literal.
But if it is a variable, I get the following:
ORA-06550: line 5, column 33:
PL/SQL: ORA-00933: SQL command not properly ended
Any ideas? I'm racking by brains where the syntax gets broken.
The syntax does not allow a variable there.
One workaround would be to construct the SELECT statement dynamically. For example:
declare
l_rc sys_refcursor;
n number := 5;
begin
-- replace "mtl_system_items" with your table...
open l_rc FOR 'select count(*) from mtl_system_items sample (' || n || ')';
-- replace call to RETURN_RESULT with whatever processing you want
DBMS_SQL.RETURN_RESULT(l_rc);
end;

Simple PL/SQL Procedure. Getting PL/SQL: SQL Statement ignored

Trying to create a very simple authentication procedure for use in Oracle APEX. My procedure is below
create or replace function pmats_authenticate(uname in varchar2, pass in varchar2)
return boolean
as
begin
declare
afound number:=0;
begin
select 1 from dual into afound;
if afound = 1 then
return true;
else
return false;
end if;
end;
end pmats_authenticate;
And I get the old PL/SQL: SQL Statement ignored thing on the select. I got the select down to the simplest thing I could think of 'select 1 from dual'. I'm scratching my head on this one I'm afraid.
The INTO clause goes before the FROM clause, so your SELECT statement should read
SELECT 1 INTO afound FROM DUAL
For reference the general structure of a SELECT is
WITH ...common table expressions...
SELECT ...fields...
INTO ...bind variables...
FROM ...tables...
INNER JOIN ...other tables... ON ...conditions...
LEFT|RIGHT|FULL OUTER JOIN ...other tables... ON ...conditions...
WHERE ...conditions...
GROUP BY ...fields...
HAVING ...conditions...
Share and enjoy.

Select Statement in oracle procedure

I can't able to create a select statement in oracle procedure. Please help me to create this.
Now I create the insert,update.delete statement in a procedure but i can't create a select statement. Please help me to create the select statement using cursor.
c_dbuser OUT SYS_REFCURSOR
ELSIF (TYPE_ =1) THEN
OPEN c_dbuser FOR
SELECT * FROM tbl_discount_master ;
CLOSE c_dbuser;
END IF;
call procedure_name(xx,xx,xx,1);
how can i get the selected value using call procedure statement.
In addition to the other suggestion, you have this solution when you are getting exactly one row.
DECLARE
myvar1 mytable.mycolumn1%TYPE;
myvar2 mytable.mycolumn2%TYPE;
BEGIN
SELECT mycolumn1, mycolumn2
INTO myvar1, myvar2
FROM mytable
WHERE …;
END;
This will throw an exception if there is no selected row (NO_DATA_FOUND) or if there is more than one row (TOO_MANY_ROWS).
The difference between select and the insert/update/delete is that you need to select into some structure, either one or more variables or a rowtype variable.
Avoid explicit cursors whenever possible in favour of the faster, less verbose and less error prone implicit cursor.
eg.
for cur_my_query in
select column1,
column2,
...
from ...
where ...
loop
refer here to cur_my_query or my_query.column1 etc
end loop

How to locate the accurate postion in pl/sql promptly (ORA-06502: PL/SQL)

I have a select statement which needs to select dozens of column into self-defined variable in my pl/sql. Like as below:
select col1,
col2,
....
col30
into var1,
...
var30
from table
where ....
While executing the SP I encounter the error:
ORA-06502: PL/SQL: numeric or value error: character string buffer too
small
The error information only points out the first line number of select statement. Even if i can figure out that my defined variable is too small to hold the column, it still makes me hard to locate the error-defined variable precisely. This is not an efficient way for me to debug this sp.
Is there any better idea, please advise me.
Two options are typically used in pl/sql:
1.Define your variables in PL/SQL to match the table's definition, using %type.
define
v_col1 my_table.col1%type;
v_col2 my_table.col2%type;
begin
select col1,col2
into v_col1, v_col2
from my_table
-- some condition that pulls 1 row
where rownum = 1;
end;
2.Define a row variable, using %rowtype
define
v_my_table_row my_table%rowtype;
begin
select *
into v_my_table_row
from my_table
where rownum = 1;
end;

Resources