Cheking if an entry exists in another table using cursor - sql

My task is to insert entries from one table to another by using parametrized cursor. Here's what I have tried
DECLARE
oldroll NUMBER;
newroll NUMBER;
oldname VARCHAR2(25);
newname VARCHAR2(25);
CURSOR c_orollcall (roll_no NUMBER,name VARCHAR2) IS SELECT * FROM o_rollcall;
PROCEDURE procedure_2;
PROCEDURE procedure_2 AS
BEGIN
OPEN c_orollcall;
LOOP
FETCH c_orollcall INTO oldroll ,oldname;
SET #count = 0;
SELECT roll_no INTO #count FROM n_rollcall WHERE EXISTS (oldroll);
IF #count>0 THEN
DBMS_OUTPUT.PUT_LINE('ENTRY ALREADY EXISTS');
ELSE
INSERT INTO n_rollcall VALUES (oldroll,oldname);
END IF;
EXIT WHEN c_orollcall%NOTFOUND;
END LOOP;
CLOSE c_orollcall;
END;
/
BEGIN
procedure_2;
END
/
I am getting a bunch of errors and dont' understand how to proceed further.I previously posted a question about this too but it generated more errors .
here's the problem statement:
Write a PL/SQL block of code using parameterized Cursor that will merge the data available in
the newly created table N_RollCall with the data available in the table O_RollCall. If the data in
the first table already exist in the second table then that data should be skipped.

I would suggest you to use an extra variable to store the result and check it in IF codition
SET count = 0;
SELECT COUNT(roll_no) INTO count FROM n_rollcall WHERE EXISTS (oldroll);
Updated code:
CREATE OR REPLACE PROCEDURE procedure_2 AS
DECLARE count INT default 0;
BEGIN
OPEN c_orollcall;
LOOP
FETCH c_orollcall INTO oldroll ,oldname;
SET count = 0;
SELECT roll_no INTO count FROM n_rollcall WHERE EXISTS (oldroll);
IF count>0 THEN
DBMS_OUTPUT.PUT_LINE('ENTRY ALREADY EXISTS');
ELSE
INSERT INTO n_rollcall VALUES (oldroll,oldname);
END IF;
EXIT WHEN c_orollcall%NOTFOUND;
END LOOP;
CLOSE c_orollcall;
END;
/

Related

Populate an Associative Array inside a Nested Table

In relation to my Previous Question, Include RowId value in Nested Table,
I have the below sample table:
create table data_test
(
data_id number,
data_value varchar2(100),
batch_name varchar2(100)
);
I have used this table as a parameter which includes the rowid:
create or replace package dat_pkg is
type typ_dat_rec is record (
data_rec data_test%rowtype,
data_rowid rowid);
type typ_dat_tst is table of typ_dat_rec index by pls_integer;
procedure transform_dat (p_batch_name data_test.batch_name%type);
procedure proc_test (p_dat typ_dat_tst);
end dat_pkg;
/
Using the procedure transform_dat, I want to populate the variable l_dat_rec with the filtered records from the data_test table, transform the data, and finally update the records using the proc_test procedure:
create or replace package body dat_pkg is
procedure transform_dat (p_batch_name data_test.batch_name%type)
is
cursor cur_dat is
select rowid, a.*
from data_test a
where batch_name = p_batch_name;
l_dat_rec typ_dat_tst;
begin
open cur_dat;
fetch cur_dat
BULK COLLECT
into l_dat_rec;
close cur_dat;
-- Do the Transformation here. Example --
for i in l_dat_rec.count loop
if l_dat_rec(i).data_value = 'hello' then
l_dat_rec(i).data_id := l_dat_rec(i).data_id + l_dat_rec(i).data_id;
else
l_dat_rec(i).data_id := l_dat_rec(i).data_id * l_dat_rec(i).data_id;
end if;
end loop;
-- update the table
proc_test (p_dat => l_dat_rec);
end transform_dat;
procedure proc_test (p_dat typ_dat_tst)
is
begin
for i in 1..p_dat.count loop
update data_test
set data_value = p_dat(i).data_value
where data_id = p_dat(i).data_id
and rowid = p_dat(i).data_rowid;
end loop;
end proc_test;
end dat_pkg;
/
however i am getting the error PLS-00597: expression 'L_DAT_REC' in the INTO list is of wrong type. The same error is being raised when i use BULK COLLECT.
What should I use to populate l_dat_rec?
In the answer to your previous question, I mentioned that populating the collection would be harder with the %rowtype field. As far as I'm aware, unless you declare an SQL-level object type instead of a record type you can't use bulk collect for this (though it's worth checking if that has changed in 12c perhaps).
I believe you are stuck with using a simpler cursor loop that builds the two fields in your type (i.e. the %rowtype sub-field and the rowid field) separately, and then builds up the collection a line at a time:
create or replace package body dat_pkg is
procedure transform_dat (p_batch_name data_test.batch_name%type)
is
cursor cur_dat is
select rowid, a.*
from data_test a
where batch_name = p_batch_name;
l_dat_tst typ_dat_tst;
l_rec data_test%rowtype;
begin
for rec_dat in cur_dat loop
l_rec.data_id := rec_dat.data_id;
l_rec.data_value := rec_dat.data_value;
l_rec.batch_name := rec_dat.batch_name;
-- or use a counter you increment for this...
l_dat_tst(l_dat_tst.count + 1).data_rec := l_rec;
l_dat_tst(l_dat_tst.count).data_rowid := rec_dat.rowid;
end loop;
-- Do the Transformation here. Example --
for i in 1..l_dat_tst.count loop
if l_dat_tst(i).data_rec.data_value = 'hello' then
l_dat_tst(i).data_rec.data_value := 'was hello';
else
l_dat_tst(i).data_rec.data_value := 'was not hello';
end if;
end loop;
-- update the table
proc_test (p_dat => l_dat_tst);
end transform_dat;
procedure proc_test (p_dat typ_dat_tst)
is
begin
for i in 1..p_dat.count loop
update data_test
set data_value = p_dat(i).data_rec.data_value
where data_id = p_dat(i).data_rec.data_id
and rowid = p_dat(i).data_rowid;
end loop;
end proc_test;
end dat_pkg;
/
As also discussed before, the references to the sub-field-record's fields have to be qualified properly, so I've inserted .data_rec in the references in both procedures. I've changed the dummy transformation to modify the value instead of the ID, as that means no updates were ever going to happen.
Demo with some dummy data:
insert into data_test values (1, 'hello', 'test');
insert into data_test values (2, 'hello', 'test');
insert into data_test values (3, 'hello', 'exclude');
insert into data_test values (4, 'goodbye', 'test');
exec dat_pkg.transform_dat('test');
select * from data_test;
DATA_ID DATA_VALUE BATCH_NAME
---------- -------------------- --------------------
1 was hello test
2 was hello test
3 hello exclude
4 was not hello test

sql insert procedure: insert values into table and control if value is existing in another table

I have little problem. I am trying to insert value into table. This is working. But I would like to control if value id_trainer is existing in another table. I want this -> execute insertClub(1, 5, 'someName'); -> and if id_trainer 5 not exists in table Trainer, procedure gives me message about this. (I tried to translate it into eng. lng., so you can find some gramm. mistakes)
create or replace procedure insertClub
(id_club in number, id_trainer in number, clubName in varchar2)
is
begin
declare counter number;
select count(*) into counter from trianer tr where tr.id_trainer = id_trainer;
if counter = 0 then
DBMS_OUTPUT.PUT_LINE('Trainer with this ID not exists');
end if;
insert into club values(id_club, id_trainer, clubName);
exception
when dup_val_on_index then
DBMS_OUTPUT.PUT_LINE('Dup ID');
end;
/
There is some error in the procedure. Please run below code to create procedure:
create or replace procedure insertClub
(id_club in number, id_trainer in number, clubName in varchar2)
is
counter number;
begin
select count(*) into counter from trianer tr where tr.id_trainer = id_trainer;
if counter = 0 then
DBMS_OUTPUT.PUT_LINE('Trainer with this ID not exists');
end if;
insert into club values(id_club, id_trainer, clubName);
exception
when dup_val_on_index then
DBMS_OUTPUT.PUT_LINE('Dup ID');
end;
/

If table have 0 rows exit procedure

I have a procedure inside a package and I want to implement a logic, wich will not insert the temp table into the main table if the temp table have 0 rows, and then go to the next procedure of the package.
IF (not exists(select 1 from temp)) THEN
RETURN;
ELSE
EXECUTE IMMEDIATE 'TRUNCATE TABLE main';
INSERT --+APPEND
INTO main
Select * from temp;
EXECUTE IMMEDIATE 'TRUNCATE TABLE temp';
END IF;
With this solution, the package is compiled with error.
Can anyone give me some tips?
you can use loop, without any variables, just first iteration, something like this
FOR a in (select 1 from temp where rownum = 1) LOOP
EXECUTE IMMEDIATE 'TRUNCATE TABLE main';
INSERT --+APPEND
INTO main
Select * from temp;
EXECUTE IMMEDIATE 'TRUNCATE TABLE temp';
END LOOP;
Just count one row and then test whether the result is 0 or 1:
declare
l_row_check integer := 0;
begin
select count(*) into l_row_check from main
where rownum = 1;
if l_row_check = 0 then
execute immediate 'truncate table main';
insert --+ append
into main
select * from temp;
execute immediate 'truncate table temp';
end if;
end;
The easiest is to use a variable to check:
--- suggested edit: add condition to select 1 row at most and avoid
-- counting big table.
select count(1) into v_count from temp where rownum <=1;
IF (v_count=0) THEN
RETURN;
ELSE
EXECUTE IMMEDIATE 'TRUNCATE TABLE main';
INSERT --+APPEND
INTO main
Select * from temp;
EXECUTE IMMEDIATE 'TRUNCATE TABLE temp';
END IF;
Some answer on here use a SELECT INTO method, but I find those a bit tricky.
Since if for example SELECT ColumnA INTO vcColumnA FROM Temp will not have any records, you will end up with the error ORA-01403: no data found.
And those can be hard to find if you have a bigger database.
To loop through a table and do something with values I think cursors and records are more safe.
For example:
DECLARE
CURSOR cTemp IS
SELECT ColumnA, ColumnB
FROM Temp;
rTemp cTemp%ROWTYPE;
BEGIN
OPEN cTemp;
LOOP
FETCH cTemp INTO rTemp;
-- Exit when we read all lines in the Temp table.
EXIT WHEN cTemp%NOTFOUND;
--Do something with every row.
--For example, print ColumnB.
DBMS_OUTPUT.PUT_LINE(rTemp.ColumnB);
END LOOP;
CLOSE cTemp;
END;
/

Executing anonymous block PlSQL fail

I want to execute an pl/sql script via terminal but I can't manage to get it to work. It first checks whether an user exists and if he does then it copies data from some table of that user.
Problem arises when there is no user - script doesn't work because it says that table or view does not exist, and that means it somehow precompiles it, while I want it to execute line by line.
Here it is:
DECLARE
v_count INTEGER := 0;
BEGIN
SELECT COUNT (1) INTO v_count FROM SYS.DBA_USERS WHERE username = UPPER ('B');
if v_count = 0 then
DBMS_OUTPUT.put_line ('Fail');
else
insert into A.some_table (some_column)
select some_column from B.some_table
where some_column = "x";
end if;
END;
/
it throws error that table does not exist at line select some_column from B.some_table because while it indeed does not exist (the user does not) the script wouldn't actually go there.
You need to use dynamic PL/SQL for the insert, so that it is not validated at compile time but only at runtime:
DECLARE
v_count INTEGER := 0;
BEGIN
SELECT COUNT (1) INTO v_count FROM SYS.DBA_USERS WHERE username = UPPER ('B');
if v_count = 0 then
DBMS_OUTPUT.put_line ('Fail');
else
EXECUTE IMMEDIATE
'insert into A.some_table (some_column)
select some_column from B.some_table
where some_column = ''x''';
end if;
END;
/

Oracle: IN function within an IF block

I have a cursor c2, with one column 'note', containing numbers.
I want to check, whether the column contains 5 and change my local variable if so.
this:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
IF c2.note IN(5) THEN
result := 'contains 5';
DBMS_OUTPUT.PUT_LINE(result);
END;
/
doesnt work.
please help!
In your code, you're declaring a cursor but you are never opening it and never fetching data from it. You'd need, presumably, some sort of loop to iterate through the rows that the cursor returned. You'll either need to explicitly or implicitly declare a record into which each particular row is fetched. One option to do that is something like
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
FOR rec IN c2
LOOP
IF rec.note IN(5) THEN
result := 'contains 5';
DBMS_OUTPUT.PUT_LINE(result);
END IF;
END LOOP;
END;
/
Note that you also have to have an END IF that corresponds to your IF statement. Naming a cursor c2 is also generally a bad idea-- your variables really ought to be named meaningfully.
You have too loop over the records/rows returned in the cursor; you can't refer to the cursor itself like that:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
FOR r2 IN c2 LOOP
IF r2.note = 5 THEN -- IN would also work but doesn't add anything
result := 'contains 5';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE(result);
END;
/
But if you're just testing for the existence of any record with value 5 then you don't need a cursor:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
BEGIN
SELECT max('contains 5')
INTO result
FROM student
WHERE note = 5;
DBMS_OUTPUT.PUT_LINE(result);
END;
/
If there are any rows with five you'll get the 'contains 5' string; if not you'll get null. The max() stops an exception being thrown if there are either zero or more than one matching records in the table.
You are missing an END IF and need to LOOP over the cursor. The procedure name is included in the final END.
But using IN should work. Like this:
CREATE OR REPLACE PROCEDURE proc
IS
result varchar(50);
cursor c2 is
SELECT note
FROM student;
BEGIN
FOR rec in c2
LOOP
IF rec.note IN (5) THEN
result := 'contains 5';
END IF;
END LOOP;
DBMS_OUTPUT.PUT_LINE(result);
END proc;
/