PL/SQL: How to insert depending on column value - oracle

I'm a novice at PL/SQL. I have attempted various approaches to use a Cursor to insert into a temp table depending on whether or not the value already exists in the temp table. I either get too many rows or nothing is inserted.
This is my last pseudocode approach and is the bare essence of what I'm attempt to accomplish:
DB: Oracle 12
Using SQL Developer
Goal: Take duplicate accountno info from table1 and merge / combine into single row in temptable
1. Add initial accountno info if it doesn’t already exists in temptable
2. If accountno exists in temptable add the additional info to accountno row
Suggestions are greatly appreciated.
Pseudocode
Declare
V_cnt number (20);
CURSOR c1 is select * from table1;
C1d c1%rowtype;
BEGIN
--
OPEN C1;
LOOP
FETCH C1 INTO c1d;
EXIT WHEN C1%NOTFOUND;
-- Limit attempts
IF LINE > 5 THEN EXIT; END IF;
select accountno INTO v_cnt from table1 where Exists(select 1 from temptable where accountno <> c1d.accountno);
IF v_cnt is NULL THEN
INSERT INTO temptable (accountno)
values(c1d.accountno);
END IF;
LINE:= LINE + 1;
END LOOP;
CLOSE C1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line ('NO DATA');
END;

If you strictly want to correct your pseudo code, You may try -
Declare
V_cnt number (20);
CURSOR c1 is select * from table1;
C1d c1%rowtype;
BEGIN
--
OPEN C1;
LOOP
FETCH C1 INTO c1d;
EXIT WHEN C1%NOTFOUND;
-- Limit attempts
IF LINE > 5 THEN
EXIT;
END IF;
BEGIN
SELECT accountno
INTO V_cnt
FROM temptable
WHERE accountno = c1d.accountno
AND ROWNUM = 1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
V_cnt := NULL;
END;
IF V_cnt is NULL THEN
INSERT INTO temptable (accountno)
values(c1d.accountno);
END IF;
LINE:= LINE + 1;
END LOOP;
CLOSE C1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line ('NO DATA');
END;
I would strongly recommend to use below pseudo code -
Declare
V_cnt number (20);
CURSOR c1 is select * from table1;
C1d c1%rowtype;
BEGIN
--
OPEN C1;
LOOP
FETCH C1 INTO c1d;
EXIT WHEN C1%NOTFOUND;
-- Limit attempts
IF LINE > 5 THEN
EXIT;
END IF;
MERGE INTO temptable
USING table1
ON (accountno = c1d.accountno)
WHEN NOT MATCHED THEN
INSERT (accountno)
values(c1d.accountno);
LINE:= LINE + 1;
END LOOP;
CLOSE C1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line ('NO DATA');
END;

Related

PL/SQL Nested Loops with cursors

I am working with Oracle PL/SQL. There are two cursors, namely c1 and c2.
v_temp VARCHAR(50);
For s1 IN c1
LOOP
--do something
FOR s2 IN c2
LOOP
--do something
v_temp := s1.s2.xxx; --PLS-00302: component 's2' must be declared
END LOOP;
END LOOP;
s2.xxx gives a column name, and with that column name I hope to assign the value of that column from s1 to v_temp.
For example:
In the first iteration, s2.xxx is 'column1',
I would like to assign s1.column1 to v_temp. In the second iteration, s2.xxx is 'column2', I would then like to assign s1.column2 to v_temp.
I got the error:
Error(191,48): PLS-00302: component 's2' must be declared
while trying to compile. I know that s1.s2.xxx is not valid, but is there another way of writing it that can make it work?
You need to fetch from a REF CURSOR and dynamically append the column_name to the select statement while opening the cursor. Here I am fetching all the column names from USER_TAB_COLUMNS for table EMPLOYEES and assigning their corresponding values to v_temp.
SET SERVEROUTPUT ON;
DECLARE
v_temp VARCHAR(50);
query1 VARCHAR2(1000);
c1 SYS_REFCURSOR;
CURSOR c2
IS
SELECT COLUMN_NAME xxx FROM USER_TAB_COLUMNS WHERE TABLE_NAME = 'EMPLOYEES';
BEGIN
FOR s2 IN c2
LOOP
--do something
query1 := 'SELECT ' ||s2.xxx||' FROM EMPLOYEES';
OPEN c1 FOR query1 ;
LOOP
FETCH c1 INTO v_temp;
DBMS_OUTPUT.PUT_LINE('COLUMN:'||s2.xxx||', VALUE:'|| v_temp);
EXIT
WHEN c1%NOTFOUND;
END LOOP;
CLOSE c1;
END LOOP;
END;
/
Since lengths of all the columns of Employees are < 50 , it is working Fine.The conversion happens implicitly for NUMBER and DATE data types.
Here is a sample Output.
COLUMN:EMPLOYEE_ID, VALUE:100
COLUMN:EMPLOYEE_ID, VALUE:101
COLUMN:EMPLOYEE_ID, VALUE:102
COLUMN:FIRST_NAME, VALUE:Eleni
COLUMN:FIRST_NAME, VALUE:Eleni
COLUMN:LAST_NAME, VALUE:Whalen
COLUMN:LAST_NAME, VALUE:Fay
COLUMN:HIRE_DATE, VALUE:17-06-03
COLUMN:HIRE_DATE, VALUE:21-09-05
I think you need smth like that:
declare
v_temp VARCHAR(50);
v_temp_1 VARCHAR(50);
cursor c2(p VARCHAR) is
SELECT *
FROM tbl
WHERE tbl.column = p;
begin
For s1 IN c1
LOOP
--do something
v_temp_1 := s1.xxx;
FOR s2 IN c2(v_temp_1)
LOOP
--do something
v_temp := s1.xxx;
END LOOP;
END LOOP;
end;

how to fetch cursor values into an object

I want to fetch values from a cursor and store them in an object....
I tried doing the same with Record i got the output
DECLARE
CURSOR lc_emp_fetch
IS
SELECT emp_no,emp_name FROM maniemp;
TYPE r_emp_record IS RECORD (
eno maniemp.emp_no%TYPE,
ename maniemp.emp_name%TYPE
);
TYPE t_emp IS TABLE OF r_emp_record;
lt_emp_rcd t_emp;
BEGIN
OPEN lc_emp_fetch;
LOOP
FETCH lc_emp_fetch BULK COLLECT INTO lt_emp_rcd LIMIT 5;
EXIT WHEN lt_emp_rcd.COUNT=0;
FOR indx IN 1..lt_emp_rcd.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(lt_emp_rcd(indx).eno||lt_emp_rcd(indx).ename);
END LOOP;
END LOOP;
CLOSE lc_emp_fetch;
END;
/
but when i try doing the same in an object its not working... i surfed all the websites but didn't get proper example program. This is my object:
CREATE OR REPLACE TYPE Typename3 AS OBJECT (
eno number,
ename varchar2(500),
esal number);
SHOW ERRORS;
I am new to this i don't know how to do this can someone help me with this
If you want to try the above example with an object and type then you should create both are at schema level it means
CREATE OR REPLACE type R_EMP_OBJECT as object(
eno number,
ename varchar2(30)
);
and
`create or replace type t_emp IS TABLE OF r_emp_object`;
then
DECLARE
lt_emp_rcd t_emp;
BEGIN
select r_emp_object (emp,ename) bulk collect into lt_emp_rcd
FROM emp;
FOR indx IN 1..lt_emp_rcd.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(lt_emp_rcd(indx).eno||lt_emp_rcd(indx).ename);
END LOOP;
END;
Edit I have tried with cursors, the below code is working fine
DECLARE
CURSOR C1
IS
SELECT emp_no,emp_name FROM maniemp;
C2 C1%ROWTYPE;
LT_EMP_RCD T_EMP;
BEGIN
OPEN C1;
LOOP
FETCH C1 INTO C2 ;
SELECT R_EMP_OBJECT(C2.EMP_NO,C2.EMP_NAME) BULK COLLECT INTO LT_EMP_RCD FROM DUAL;
EXIT WHEN C1%NOTFOUND;
FOR INDX IN 1..LT_EMP_RCD.COUNT
LOOP
DBMS_OUTPUT.PUT_LINE(LT_EMP_RCD(INDX).ENO||' '||LT_EMP_RCD(INDX).ENAME);
END LOOP;
END LOOP;
CLOSE C1;
END;

How to fetch the cursor data in oracle stored procedure

create or replace
PROCEDURE get_new
AS
CUST_ID varchar2(100);
ROUTERNAME_N VARCHAR2(100);
BEGIN
CURSOR c1 IS
SELECT TRAFFIC_CUST_ID,ROUTERNAME INTO CUST_ID,ROUTERNAME_N
FROM INTERFACE_ATTLAS
WHERE rownum > 3;
my_ename INTERFACE_ATTLAS.TRAFFIC_CUST_ID%TYPE;
my_salary INTERFACE_ATTLAS.ROUTERNAME%TYPE;
LOOP
FETCH c1 INTO my_ename;
FETCH c1 INTO my_salary;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(my_ename);
end loop;
end;
I am new to oracle and stored procedure. I am trying to get the rows using cursor fetch, and getting following error:
PLS-00103: Encountered the symbol "C1" when expecting one of the following:
:= . ( # % ;
Rewrite it like this:
create or replace
PROCEDURE get_new
AS
my_ename INTERFACE_ATTLAS.TRAFFIC_CUST_ID%TYPE;
my_salary INTERFACE_ATTLAS.ROUTERNAME%TYPE;
CURSOR c1 IS
SELECT TRAFFIC_CUST_ID,ROUTERNAME
FROM INTERFACE_ATTLAS
WHERE rownum > 3;
BEGIN
open c1;
LOOP
FETCH c1 INTO my_ename, my_salary;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(my_ename);
end loop;
close c1;
end;
Do not forget to open and close cursors. It always will print nothing because of rownum > 3; You wanted to type: rownum < 3;, didn't you?
create or replace
PROCEDURE get_new
AS
CUST_ID varchar2(100);
ROUTERNAME_N VARCHAR2(100);
BEGIN
CURSOR c1 IS
SELECT TRAFFIC_CUST_ID,ROUTERNAME INTO CUST_ID,ROUTERNAME_N
FROM INTERFACE_ATTLAS
WHERE rownum > 3;
my_ename INTERFACE_ATTLAS.TRAFFIC_CUST_ID%TYPE;
my_salary INTERFACE_ATTLAS.ROUTERNAME%TYPE;
LOOP
FETCH c1 INTO my_ename;
FETCH c1 INTO my_salary;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(my_ename);
end loop;
end;
Cursor should be declare in the declaration part. Then have to open in begin-end section. In the declaration section you can not assign value to variable. When you are fetching value you can not select randomly value form cursor,
modified code:
create or replace
PROCEDURE get_new
AS
no mean --CUST_ID varchar2(100);
no means -- ROUTERNAME_N VARCHAR2(100);
CURSOR c1 IS
SELECT deptno,job
FROM emp;
my_ename emp.deptno%TYPE;
my_salary emp.job%TYPE;
BEGIN
open c1;
LOOP
fetch c1 into my_ename,my_salary;
-- FETCH c1 INTO my_ename;
--FETCH c1 INTO my_salary;
EXIT WHEN c1%NOTFOUND;
DBMS_OUTPUT.PUT_LINE(my_ename);
end loop;
end;
execute get_new.
You should probably declare your cursor and your variables my_ename and my_salary in the dedicated section, i.e. before the BEGIN, and then open your cursor:
IS
CUST_ID varchar2(100);
ROUTERNAME_N VARCHAR2(100);
C1 sys_refcursor;
my_ename INTERFACE_ATTLAS.TRAFFIC_CUST_ID%TYPE;
my_salary INTERFACE_ATTLAS.ROUTERNAME%TYPE;
BEGIN
OPEN C1 for
SELECT ...
You would have to declare the Cursor before BEGIN. You would use no INTO clause in the cursor declaration. Then you would have to OPEN the cursor. Then you would FETCH INTO my_ename, my_salary, not one after the other (you fetch rows, not columns). WHERE rownum > 3 returns no rows. As you don't want a first row, you will never get a second, third and fourth either.
And you can use an implicit cursor which is easier to deal with (no need to open, fetch and close explicitely):
BEGIN
FOR rec IN
(
select traffic_cust_id, routername
from interface_attlas
where rownum <= 3
) LOOP
DBMS_OUTPUT.PUT_LINE(rec.traffic_cust_id || ': ' || rec.salary);
END LOOP;
END;

get next value of cursor if the column not found?

I am looping through cursor using record, but when this loop is unable to find a value,
it stops executing the script. So is there anyway to let the loop continue if record is empty ?
declare
cust_id info.CUSTOMER_ID%type;
SPNum info.spnumber%type;
EnterTicketDate EnteryDate%type;
cursor mycursor is
select S_P_NUM ,_START_TIME
from info
where UPPER (STATUS)='YES';
begin
for myRecord in mycursor
loop
dbms_output.put_line(SPNum);
select PID into cust_id from info where dn_num=SPNum;
dbms_output.put_line('ID is '|| cust_id);
end loop;
end;
I am thinking about avoiding this case by handing the data_not_found and move to the next value of the loop but how and is it possible ?
can I use the nextval keyword anyway?
declare
cust_id info.CUSTOMER_ID%type;
SPNum info.spnumber%type;
EnterTicketDate EnteryDate%type;
cursor mycursor is
select S_P_NUM ,_START_TIME
from info
where UPPER (STATUS)='YES';
begin
for myRecord in mycursor
loop
dbms_output.put_line(SPNum);
select PID into cust_id from info where dn_num=SPNum;
dbms_output.put_line('ID is '|| cust_id);
exit when myRecord%notfound;
end loop;
exception
when data_not_found
-- here is a recall for the next value of my record
end;
When CURSOR returns NO_DATA_FOUND it means no more data to read from it.
for myRecord in mycursor
loop
-- exit when myRecord%notfound;
/* NOT NEEDED as FOR LOOP itself will terminate on NO DATA in mycursor */
dbms_output.put_line(SPNum);
select PID into cust_id from info where dn_num=SPNum;
dbms_output.put_line('ID is '|| cust_id);
end loop;
Hope you need this.
declare
cust_id info.CUSTOMER_ID%type;
SPNum info.spnumber%type;
EnterTicketDate EnteryDate%type;
cursor mycursor is
select S_P_NUM ,_START_TIME
from info
where UPPER (STATUS)='YES';
begin
for myRecord in mycursor
loop
IF(myRecord.S_P_NUM IS NOT NULL)
THEN
BEGIN
dbms_output.put_line(myRecord.S_P_NUM);
select PID into cust_id from info where dn_num=myRecord.S_P_NUM;
dbms_output.put_line('ID is '|| cust_id);
EXCEPTION WHEN NO_DATA_FOUND THEN
dbms_output.put_line('NOT FOUND FOR SPNum '|| myRecord.S_P_NUM);
CONTINUE; -- Process Next S_P_NUM from cursor
END;
END IF;
end loop;
END;

how to make a loop for all columns of a table?

I have a table EMPLOYEES, i need to make a loop, on every step of the loop I use dbms_output.put_line(column_name)
How can I make this?
Just found this solution
begin
for rec in (SELECT column_name
FROM all_tab_columns
WHERE owner = 'HR'
AND table_name = 'EMPLOYEES')
loop
dbms_output.put_line(rec.column_name);
end loop;
end;
Try to use cursor as below:
set serveroutput on;
declare
var_col1 varchar2(30) ;
num_col2 number ;
CURSOR cur
is
select var_col ,num_col
from table
where <conditions>;
begin
open cur;
fetch cur into var_col1,num_col2;
LOOP
fetch cur into var_col1,num_col2;
EXIT WHEN cur%NOTFOUND;
dbms_output.put_line( var_col1||' '||num_col2);
END LOOP;
close cur;
end;
here is another solution:
set serveroutput on;
begin
FOR cur in ( select var_col ,num_col from table where <conditions>)
LOOP
dbms_output.put_line(cur.var_col||' = '||cur.num_col);
END LOOP;
end;
Of course You can rewrite this SELECT example with WHERE after table_name. I dont compiled this code but I thinks its OK. Change ID_Employee and Name for your atributes
CREATE OR REPLACE PROCEDURE AAA_TEST
IS
BEGIN
DECLARE
v_id NUMBER :=0;
v_name VARCHAR2(25);
CURSOR cursorMails IS
SELECT Id_Employee,Name FROM EMPLOYEES;
BEGIN
OPEN cursorMails;
LOOP
FETCH cursorMails INTO v_id, v_name;
DBMS_OUTPUT.PUT_LINE('Number of Employee: ' || v_id || ' Name Employee: ' || v_name);
EXIT WHEN cursorMails%NOTFOUND;
END LOOP;
CLOSE cursorMails;
END;
END;
/

Resources