Oracle - NO_DATA_FOUND error, but there is data - oracle

I have a PL/SQL block that I put into a stored procedure so that I can debug it. Here is a bit of pseudocode to describe the PL/SQL block:
CREATE OR REPLACE PROCEDURE SPROC_A AS
CURSOR CURSOR_A IS
SELECT ID, YEAR
FROM TABLE_A;
vNAME VARCHAR2(200) := NULL;
BEGIN
FOR REC IN CURSOR_A LOOP
BEGIN
SELECT NVL(B.FIELD_1, B.FIELD_2) INTO vNAME --the sproc breaks here--
FROM TABLE_B B
WHERE B.ID = REC.ID
AND B.YEAR = REC.YEAR
EXCEPTION
WHEN NO_DATA_FOUND THEN
vNAME := NULL;
END;
UPDATE TABLE_C C
SET C.NAME = vNAME
WHERE C.ID = REC.ID
AND C.YEAR = REC.YEAR;
END LOOP;
END;
If I run this portion independently and supply my own values for REC.ID and REC.YEAR, data is returned:
SELECT NVL(B.FIELD_1, B.FIELD_2) --INTO vNAME
FROM TABLE_B B
WHERE B.ID = REC.ID
AND B.YEAR = REC.YEAR
Furthermore, the variable into which I am trying to select data is of datatype VARCHAR2(200) - TABLE_B.FIELD_1 and TABLE_B.FIELD_2 are both of datatype VARCHAR2(40), so there shouldn't be a mismatch of datatypes.
What else could I be missing here?

Related

Update a table with dynamic query using bulk collect

I want update a table using a dynamic query, cursor and bulk collect. But I don't know the syntax:
declare
my_cursor ?;
-- other objects;
begin
execute immediate
"select s.col1, s.col2, rowid, d.rowid
from source_table s, destination_table d
where s.id = d.id "
BULK COLLECT INTO my_cursor;
FORALL i IN my_cursor.FIRST..my_cursor.LAST
UPDATE destination_table set col_a=my_cursor(i).col1 , col_b=my_cursor(i).col2
WHERE rowid = my_cursor(i).rowid;
commit;
end;
what would be the correct syntax and oracle objects
please help.
You can use something like this:
declare
type REC_TYPE is record (
ID SOURCE_TABLE.ID%type,
COL1 SOURCE_TABLE.COL1%type,
COL2 SOURCE_TABLE.COL2%type
);
type REC_CURSOR is ref cursor;
ref_cursor REC_CURSOR;
rec REC_TYPE;
sql_query VARCHAR2(4000);
begin
sql_query := 'select s.ID, COL1, COL2 from SOURCE_TABLE s, DESTINATION_TABLE d where s.ID = d.ID';
open ref_cursor for sql_query;
loop
fetch ref_cursor into rec;
exit when ref_cursor%NOTFOUND;
update DESTINATION_TABLE
set COL_A = rec.COL1, COL_B = rec.COL2
WHERE ID = rec.ID;
end loop;
close ref_cursor;
commit;
end;
/
or with bulk collect:
declare
type REC_TYPE is record (
ID SOURCE_TABLE.ID%type,
COL1 SOURCE_TABLE.COL1%type,
COL2 SOURCE_TABLE.COL2%type
);
type REC_TYPES is table of REC_TYPE;
type REC_CURSOR is ref cursor;
ref_cursor REC_CURSOR;
recs REC_TYPES;
sql_query VARCHAR2(4000);
begin
sql_query := 'select s.ID, COL1, COL2 from SOURCE_TABLE s, DESTINATION_TABLE d where s.ID = d.ID';
open ref_cursor for sql_query;
fetch ref_cursor bulk collect into recs;
close ref_cursor;
FOR ind IN recs.FIRST .. recs.LAST
loop
update DESTINATION_TABLE
set COL_A = recs(ind).COL1, COL_B = recs(ind).COL2
WHERE ID = recs(ind).ID;
end loop;
commit;
end;
/

The function PL/SQL doesn't return any value

I have the next PL/SQL code:
create or replace FUNCTION NUMBER_PLATES (name VARCHAR2)
RETURN INT
IS
num_plates INT;
BEGIN
SELECT count(*) INTO num_plates
FROM plate p, detail_ped dt
WHERE dt.plate = p.cod_plate AND p.name = name;
RETURN (num_plates);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('ERROR');
END NUMBER_PLATES;
The next is execute the function into SQL Commands:
DECLARE a INT;
BEGIN
a := NUMBER_PLATES('chicken');
DBMS_OUTPUT.PUT_LINE(a);
END;
But the function returns me 0 when really is 3.
What am I doing wrong?
If I execute my SQL sentence returns 3:
SELECT count(*)
FROM plate p, detail_ped dt
WHERE dt.plate = p.cod_plate AND p.name = 'chicken';
You should rename parameter name to avoid name collision:
create or replace FUNCTION NUMBER_PLATES (p_name VARCHAR2)
RETURN INT
IS
num_plates INT;
BEGIN
SELECT count(*) INTO num_plates
FROM plate p
JOIN detail_ped dt -- proper JOIN syntax
ON dt.plate = p.cod_plate
WHERE p.name = p_name;
RETURN (num_plates);
-- exception is dead code, COUNT(*) will return 0 if no records found
-- EXCEPTION
-- WHEN NO_DATA_FOUND THEN
-- DBMS_OUTPUT.PUT_LINE('ERROR');
END NUMBER_PLATES;
/
db<>fiddle demo

How to get the number of rows in ROWTYPE variable

I have two tables Table1 an dTable2 that have identical columns. I need to check if a particular id is in one of them and return the row of data from whichever table.
I have the following PL/SQL code:
v_result Table1%ROWTYPE;
BEGIN
SELECT a.*
INTO v_result
FROM Table1 a
WHERE a.id = 123;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- when record not found
SELECT b.*
INTO v_result
FROM Table2 b
WHERE b.id = 123;
END;
The issue is that the exception does not get thrown, so v_result returns no data. How can I check v_result for the number of rows?
For cursor I can use ROWCOUNT but v_result is not a cursor.
I also tried using count property but it errored out.
I changed my code to:
v_result Table1%ROWTYPE;
BEGIN
SELECT a.*
INTO v_result
FROM Table1 a
WHERE a.id = 123;
if v_result.count =0 then
SELECT b.*
INTO v_result
FROM Table2 b
WHERE b.id = 123;
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN -- when record not found
SELECT b.*
INTO v_result
FROM Table2 b
WHERE b.id = 123;
END;
And got an error component 'count' must be declared
What am I doing wrong?
You may use only a single row in a record variable. If you want to store and count multiple rows, you may define a collection of records and use BULK COLLECT INTO to load all of them at once and it won't raise a NO_DATA_FOUND. The count function works on collections.
DECLARE
TYPE type_tab1 IS TABLE OF Table1%ROWTYPE;
TYPE type_tab2 IS TABLE OF Table2%ROWTYPE;
v_result1 type_tab1;
v_result2 type_tab2;
BEGIN
SELECT a.*
BULK COLLECT INTO v_result1
FROM Table1 a
WHERE a.id = 123;
if v_result1.count = 0 then
SELECT b.* BULK COLLECT
INTO v_result2
FROM Table2 b
WHERE b.id = 123;
end if;
DBMS_OUTPUT.PUT_LINE('v_result1 ='|| v_result1.count);
DBMS_OUTPUT.PUT_LINE('v_result2 ='|| v_result2.count);
END;
/
Output for the Demo
v_result1 =0
v_result2 =1
If your intention is to simply check if a row exists, then a simpler and efficient approach would be to use EXISTS
SELECT
CASE WHEN
EXISTS (
SELECT 1
FROM table1
WHERE id = 123
) THEN 1
ELSE 0
END
INTO v_count
FROM dual;
IF v_count = 0
THEN
..
..

Assign variable to subquery result inside a PL/SQL block

Here is a bit of more simplified pseudocode describing what I am trying to do:
DECLARE
CURSOR CURSOR_A IS
SELECT FIELD_A1, FIELD_A2
FROM TABLE_A;
vNAME NVARCHAR2(100) := NULL;
BEGIN
FOR RECORD_A IN CURSOR_A LOOP
IF (RECORD_A.FIELD_A1 IS NOT NULL) THEN
vNAME := RECORD_A.FIELD_A1;
ELSE
vNAME := (SELECT FIELD_B
FROM TABLE_B
WHERE TABLE_B.B2 = RECORD_A.A2)
END LOOP;
END;
/
Am I not allowed to have a SELECT statement inside of a PL/SQL block?
All you need - one select. Try it:
declare
name nvarchar2(100) := null;
begin
for row_ in (
select field_a1, field_b from table_a left outer join table_b on b2 = a2
) loop
name := coalesce(row_.field_a1, row_.field_b);
-- do something
end loop;
end;
/
You could still add ... and field_a1 is null to the on-clause if you have too many rows in both tables and concerned about performance.
You are allowed to do select but you need to specify variable that will store selected data
DECLARE
CURSOR CURSOR_A IS
SELECT FIELD_A1, FIELD_A2
FROM TABLE_A;
vNAME NVARCHAR2(100) := NULL;
BEGIN
FOR RECORD_A IN CURSOR_A LOOP
IF (RECORD_A.FIELD_A1 IS NOT NULL) THEN
vNAME := RECORD_A.FIELD_A1;
ELSE
SELECT FIELD_B into vNAME
FROM TABLE_B
WHERE TABLE_B.B2 = RECORD_A.A2;
END LOOP;
END;
/
We required into clause to store a value of select statement inside Begin and end block.
Please look into below example highlighted line:
DECLARE
CURSOR CURSOR_A IS
SELECT FIELD_A1, FIELD_A2
FROM TABLE_A;
vNAME NVARCHAR2(100) := NULL;
BEGIN
FOR RECORD_A IN CURSOR_A LOOP
IF (RECORD_A.FIELD_A1 IS NOT NULL) THEN
vNAME := RECORD_A.FIELD_A1;
ELSE
SELECT FIELD_B into vNAME --**highlighted line**
FROM TABLE_B
WHERE TABLE_B.B2 = RECORD_A.A2
END LOOP;
END;

Getting the id for "No data found rows" in the Oracle

While querying for some of the ID in the table there are no rows.
How do I write pl/sql to get all those ID's
select type_id from table1 where pid = 123;
if type_id is null then
begin
DBMS_OUTPUT.put_line('Error ID'|| 123)
END
this doesn't work.
What is your datatype for typeid?
Assuming it is varchar2,
Try this:
DECLARE
v_type_id VARCHAR2(1000);
begin
select type_id INTO v_type_id from table1 where pid = 123;
DBMS_OUTPUT.put_line('Type Id is'|| v_type_id);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.put_line('Error ID'|| 123);
END
One way to accomplish this is to use an OUTER JOIN:
BEGIN
FOR aRow IN (SELECT p.PID
FROM PROCESSES p
LEFT OUTER JOIN TABLE1 t1
ON t1.PID = p.PID
WHERE p.PID = 123 AND
t1.TYPE_ID IS NULL)
LOOP
DBMS_OUTPUT.PUT_LINE('Error ID=' || aRow.PID);
END LOOP;
END;
Share and enjoy.

Resources