when i try this PL/SQL to execute i have the error Oracle PL/SQL - ORA-01403 "No data found" in first select in for loop
declare
CURSOR
tempRow IS SELECT t2.*
FROM TABLE2 t2
JOIN TABLE3 t3 on t3.ID = t2.ID_FB;
updateId integer;
B TABLE1.A%TYPE;
BEGIN
FOR item IN tempRow
LOOP
select t1.A, t1.ID
into B, updateId
from TABLE2 t2
JOIN TABLE1 t1 on t2.ID = t1.ID_R
WHERE t2.ID = item.ID;
-- more conditions
--- more code
dbms_output.put_line(B);
END LOOP;
END;
i can't found the wrong in the statement.
can someone help me?
It says that for ID (in tempRow cursor), which is acquired via join of table2 and table3, no rows exist in table1 which is joined to table2 in select statement within the cursor FOR loop.
To check it, include additional (nested) begin-exception-end block and display such a value, e.g.
BEGIN
FOR item IN temprow
LOOP
BEGIN
SELECT t1.a, t1.id
INTO b, updateid
FROM table2 t2 JOIN table1 t1 ON t2.id = t1.id_r
WHERE t2.id = item.id;
-- more conditions
--- more code
DBMS_OUTPUT.put_line (b);
EXCEPTION
WHEN NO_DATA_FOUND
THEN
DBMS_OUTPUT.put_line ('error on ID = ' || item.id);
END;
END LOOP;
END;
Then decide what to do; will you handle it somehow, ignore it, fix WHERE clause(s), ...
Related
I need to save values from cte into variables in the procedure.
My example:
WITH test_cte AS (
SELECT *
from(
SELECT date_a,lastName,firstName,birthDate, rank() over(ORDER BY date_a desc) rnk
FROM test_table a
join test_table b ON b.id = a.bid
)a1
WHERE rnk =1)
SELECT count(*) into count_a
FROM test_table a
join test_table b ON b.id = a.bid
WHERE a.code = code_name;
IF count_a > 0 THEN
SELECT date_a,lastName,firstName,birthDate
into date_a_var,lastName_var,firstName_var,birthDate_var
FROM test_cte;
ELSE
date_a_var := NULL;
lastName_var := NULL;
firstName_var := NULL;
birthDate_var := NULL;
END IF;
but when I try to compile it I'm getting next error:
PL / SQL: ORA-00942: table or view does not exist
on FROM test_cte;
What can I do to solve this problem?
In your code:
-- Start of first SELECT statement.
WITH test_cte AS (
SELECT *
from(
SELECT date_a,lastName,firstName,birthDate, rank() over(ORDER BY date_a desc) rnk
FROM test_table a
join test_table b ON b.id = a.bid
)a1
WHERE rnk =1
)
SELECT count(*) into count_a
FROM test_table a
join test_table b ON b.id = a.bid
WHERE a.code = code_name;
-- End of first SELECT statement.
IF count_a > 0 THEN
-- Start of second SELECT statement.
SELECT date_a,lastName,firstName,birthDate
into date_a_var,lastName_var,firstName_var,birthDate_var
FROM test_cte;
-- End of second SELECT statement.
ELSE
date_a_var := NULL;
lastName_var := NULL;
firstName_var := NULL;
birthDate_var := NULL;
END IF;
It won't work because the test_cte only exists for the one statement and when you finish the statement's final SELECT statement then it no longer exists for the subsequent statements. (However, you do not use the sub-query factoring clause [a.k.a. CTE] in the SELECT for that statement so it is not clear why you need the WITH clause.)
Instead of trying to use COUNT, just get the data and handle the NO_DATA_FOUND exception if it occurs (also, from Oracle 12, you don't need to use RANK and can use FETCH FIRST ROW WITH TIES instead):
DECLARE
date_a_var test_table.date_a%TYPE;
lastName_var test_table.lastname%TYPE;
firstName_var test_table.firstname%TYPE;
birthDate_var test_table.birthdate%TYPE;
BEGIN
BEGIN
SELECT date_a,
lastName,
firstName,
birthDate
INTO date_a_var,
lastName_var,
firstName_var,
birthDate_var
FROM test_table a
join test_table b ON b.id = a.bid
ORDER BY date_a DESC
FETCH FIRST ROW WITH TIES;
EXCEPTION
WHEN NO_DATA_FOUND THEN
date_a_var := NULL;
lastName_var := NULL;
firstName_var := NULL;
birthDate_var := NULL;
END;
-- Continue processing
END;
(Note: You may also get a TOO_MANY_ROWS exception if there are duplicate dates. Either use FETCH FIRST ROW ONLY or, before Oracle 12, the ROW_NUMBER analytic function.)
I am trying to create a trigger that fires after an insert/update and checks for null values in couple of columns. In case any one of them is NULL, it queries other tables and updates the current table
CREATE OR REPLACE TRIGGER sample_trigger
AFTER INSERT OR UPDATE
ON test_table
FOR EACH ROW
BEGIN
IF :NEW.ID IS NULL OR :NEW.CODE IS NULL
THEN
UPDATE (:NEW.ID,:NEW.CODE) = (SELECT T1.ID,
T2.CODE
FROM TABLE_1 T1
JOIN TABLE_2 T2 ON T1.ID=T2.ID
WHERE ID=:NEW.TEST_ID);
END IF;
END;
/
Warning: Trigger created with compilation errors.
ERROR: PL/SQL: ORA-00928: missing SELECT keyword
You don't UPDATE the :new pseudo-record. Just assign values to it
SELECT t1.id, t2.code
INTO :new.id, :new.code
FROM table1 t1
join table2 t2 on t1.id = t2.id
WHERE id = :new.test_id
A couple additional notes
Your WHERE clause will generate an ambiguous reference error. Since both t1 and t2 have an ID column, you'd need to specify which table's column you are comparing against.
If test_table is the same as either table_1 or table_2, that's going to produce a mutating table exception.
Your trigger should be a BEFORE INSERT since it's modifying data not an AFTER INSERT trigger.
Triggers have to follow syntax as any other program unit; UPDATE you wrote is invalid (obviously), but - you don't need it. Here's what you might have done:
declare two variables which will hold ID and CODE values
set TEST_TABLES's columns values to those variables
CREATE OR REPLACE TRIGGER sample_trigger
AFTER INSERT OR UPDATE
ON test_table
FOR EACH ROW
DECLARE
l_id test_table.id%type;
l_code test_table.code%type;
BEGIN
IF :NEW.ID IS NULL OR :NEW.CODE IS NULL
THEN
SELECT t1.id, t2.code
INTO l_id , l_code
FROM table_1 t1 JOIN table_2 t2 ON t1.id = t2.id
WHERE id = :new.test_id;
:new.id := l_id;
:new.code := l_code;
END IF;
END;
/
is it possible to define a select statement as variable, somethings like this:
Define (Select t1.id, t1.var1, t1.var2, t2.id, t2.var1, t2.var2 From
table1 t1, table2 t2 Where t1.id = t2.id) as namevariable
Thanks for your help,
Andrea
Define (Select t1.id, t1.var1, t1.var2, t2.id, t2.var1, t2.var2 From
table1 t1, table2 t2 Where t1.id = t2.id) as namevariable
You can do it as :
DECLARE
var VARCHAR2 (100);
v_emp_id number;
BEGIN
--Defining as a variable in PLSQL
var := 'Select employee_id from employee where employee_id = :1';
EXECUTE IMMEDIATE var into v_emp_id using 1 ;
--Showing the result
DBMS_OUTPUT.PUT_LINE(v_emp_id);
END;
simply with select ... into ...
DECLARE
my_id NUMBER;
my_val VARCHAR2(32);
BEGIN
SELECT t1.id, t1.val into my_id, my_val from my_table t1 where... ;
END;
Is it possible to do something like this in pl/sql for bulk insert using FORALL?
TYPE c_type1 IS RECORD
(
column1 table1.column1%TYPE,
column2 table1.column2%TYPE,
client table2.client%TYPE
);
type1 c_type1;
CURSOR cur_t IS select * BULK COLLECT INTO recs from table3 ;
begin
FOR recs IN cur_t
LOOP
SELECT * INTO type1 FROM (select a.column1, a.column2,imm.client
...
from table1 a, table2 imm
WHERE
a.column1 = recs.column1
) WHERE ROWNUM=1;
INSERT INTO table2 values (recs.column1,type1.column2);
...
P.S : There are more 80 columns to be inserted.
Your question is not pretty clear but looking at your code I have the following. Check if this is what you were looking for.
declare
CURSOR cur_t IS
select t3.column1 , t1.column2
from table3 t3
inner join table1 t1
on t3.column1 = t1.column1;
type var_cur is table of cur_t%rowtype;
var var_cur;
begin
open cur_t;
LOOP
FETCH cur_t bulk collect into var limit 100;
EXIT WHEN cur_t%NOTFOUND;
FORALL i IN 1 .. var.count SAVE EXCEPTIONS
INSERT INTO TABLE2
VALUES var(i);
END LOOP;
CLOSE distinctUserIdCursor;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('Error in Insertion of record' || '~~~~' || SQLERRM);
FOR indx IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
DBMS_OUTPUT.put_line (SQL%BULK_EXCEPTIONS (indx).ERROR_INDEX|| ': '
|| SQL%BULK_EXCEPTIONS (indx).ERROR_CODE);
END LOOP;
end;
I am trying to read values from two column1, column2 from table1 using cursor. Then I want to pass these values to another cursor or select into statement
so my PL/Sql script will use the values of these two columns to get data from another table called table2
Is this possible? And what's the best and fastest way to do something like that?
Thanks :)
Yes, it's possible to pass cursor values into variables. Just use fetch <cursor_name> into <variable_list> to get one more row from a cursor. After that you can use the variables in where clause of some select into statement. E.g.,
declare
cursor c1 is select col1, col2 from table1;
l_col1 table1.col1%type;
l_col2 table1.col2%type;
l_col3 table2.col3%type;
begin
open c1;
loop
fetch c1 into l_col1, l_col2;
exit when c1%notfound;
select col3
into l_col3
from table2 t
where t.col1 = l_col1 --Assuming there is exactly one row in table2
and t.col2 = l_col2; --satisfying these conditions
end loop;
close c1;
end;
If you use an implicit cursor, then it's even simpler:
declare
l_col3 table2.col3%type;
begin
for i in (select col1, col2 from table1)
loop
select col3
into l_col3
from table2 t
where t.col1 = i.col1 --Assuming there is exactly one row in table2
and t.col2 = i.col2; --satisfying these conditions
end loop;
end;
In these examples, it's more efficient to use a subquery
begin
for i in (select t1.col1
, t1.col2
, (select t2.col3
from table2 t2
where t2.col1 = t1.col1 --Assuming there is atmost one such
and t2.col2 = t1.col2 --row in table2
) col3
from table1 t1)
loop
...
end loop;
end;