simple way to return 2 or more rows using a SELECT in pl/sql - oracle

I am trying to figure out the most simple way to return 2 or more rows using a select statement in pl/sql to the sqlplus output. Here is a basic example.
begin
select sysdate,'12345' xid from dual
union all
select sysdate,'67890' xid from dual;
end;
/
Error is "an INTO clause is expected in this SELECT statement"

You would use a cursor to return the result of a query:
SQL> VARIABLE x REFCURSOR
SQL> BEGIN
2 OPEN :x FOR SELECT ROWNUM FROM dual CONNECT BY LEVEL <= 3;
3 END;
4 /
PL/SQL procedure successfully completed.
SQL> PRINT x
ROWNUM
----------
1
2
3

Yes, you can return a ResultSet from a PL/SQL. Take a look at this URL.

When writing a SQL code in a BEGIN-END block, you cannot display its result-set in the editor. Trim the BEGIN-END from your query, and it would happily display the results.
Basically, code within a BEGIN-END block is not used for displaying results, it is used for data processing instead. So you should simply write:
SELECT SYSDATE,'12345' XID FROM DUAL
UNION ALL
SELECT SYSDATE,'67890' FROM DUAL;
to display the result-set in your SQL editor.
Also notice that I removed alias "XID" in second SELECT statement: you need to give column aliases in only first query in a UNION/UNION ALL statement.

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 Cursor, No Data Found exception

I'm trying to modify a procedure that removes a user from the system, adding a bit that generates a list of any areas over which they are the only admin. I have read that cursors can work when 0 results are found, so I am assuming that my query is the problem. Tables 1 (A) and 2 (B&C) are joined by the primary key of table A. Subquery B is a list of all the areas a user is admin over, and Subquery C is a list of all areas with only one admin. In the specific instance I'm testing, there is no matching area_id between subqueries B and C. Is there a way I can modify this query to work properly? I tried moving the opening of the cursor behind an if statement, but still receive the error, so I'm assuming it's the declaration of the cursor that is resulting in the exception being thrown.
CURSOR AA_CUR IS
SELECT AREA_NAME
FROM FILE_TRANSFER.AREA_LU A,
(SELECT AREA_ID
FROM FILE_TRANSFER.USER_AREA_ACCESS
WHERE AREA_ADMIN='Y'
AND USERNAME IN (SELECT USERNAME
FROM FILE_TRANSFER.USER_INFORMATION
WHERE USER_INFORMATION_ID = v_UIID)) B,
(SELECT AREA_ID, AREA_ADMIN, COUNT(*)
FROM FILE_TRANSFER.USER_AREA_ACCESS
WHERE AREA_ADMIN='Y'
HAVING COUNT(*) = 1
GROUP BY AREA_ID, AREA_ADMIN) C
WHERE A.AREA_ID = B.AREA_ID
AND B.AREA_ID = C.AREA_ID;
Your assumption is wrong.
Cursor's SELECT can't return NO_DATA_FOUND. If it returns nothing, it is silently ignored, nothing happens.
SQL> declare
2 cursor c1 is
3 select 'x' from dual
4 where 1 = 2; -- this query returns "nothing"
5 c1r c1%rowtype;
6 begin
7 open c1;
8 fetch c1 into c1r;
9 close c1;
10 end;
11 /
PL/SQL procedure successfully completed.
See? Nothing happened. Just to show that query will raise NO_DATA_FOUND (if ran separately):
SQL> declare
2 l_val varchar2(1);
3 begin
4 select 'x' into l_val from dual
5 where 1 = 2; -- this will raise NO_DATA_FOUND
6 end;
7 /
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4
SQL>
Therefore, there must be some other SELECT statement that is raising that error. Which one? Can't tell as you didn't post much of your code and - even if you did - without your tables and data it would be difficult to guess.
So, what to do? Debug your code. A simple option is to put DBMS_OUTPUT.PUT_LINE calls between every two statements so that you'd see which part of code actually failed - then you'll be able to try to fix it.

If I am querying below query, getting error

Exec('select * from dual ' );
Showing invalid Sql query. Is it a valid query? If no, what could the reason and solution?
EXEC is a SQL*Plus command, used to run PL/SQL code (usually procedures).
But, if you insist on selecting from dual, no problem. Here's how: as it has to be PL/SQL, declare a variable and select into it. As DUAL has one column (named DUMMY), it'll work just fine:
SQL> var l_dum varchar2;
SQL> exec select * into :l_dum from dual;
PL/SQL procedure successfully completed.
SQL> print l_dum
L_DUM
--------------------------------
X
SQL>
What we normally do is
SQL> select * from dual;
D
-
X
SQL>
Your error? Single quotes, no variable to select into.
EXEC[UTE] IMMEDIATE must be used within an anonymous block or procedure.
For example:
Begin
Execute Immediate 'Select * From Dual';
End;
Here is a simple Youtube explanation:
https://youtu.be/47KzYVBNbIs

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

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!!

Retrieve a select count(*) in Oracle inside a cursor

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;

Resources