LOOP into cursor until each IF ELSE true in oracle - oracle

I have written a cursor where I want to LOOP each and every column until it becomes true. So if all the IF statement matches to true then I want to insert the data into VALID table or at last I want to insert the incorrect data into the INVALID TABLE.
Below is the cursor. Kindly let me know whether my step is accurate or Do I need to make any changes in that.
create or replace procedure fiber_transm_valid_data as
begin
for cur_r in (select rj_span_id,
rj_maintenance_zone_name,
rj_maintenance_zone_code
from app_fttx.transmedia#sat
)
loop
if cur_r.rj_span_id > '0' then
elsif cur_r.rj_maintenance_zone_name = 'aa' then
elsif cur_r.rj_maintenance_zone_code = 'A123' then
INSERT INTO VALID TABLE
(span_id, maintenance_zone_name,rj_maintenance_zone_code)
values (cur_r.rj_span_id, cur_r.rj_maintenance_zone_name, cur_r.rj_maintenance_zone_code);
ELSE
INSERT INTO INVALID TABLE
(span_id, maintenance_zone_name,rj_maintenance_zone_code)
values (cur_r.rj_span_id, cur_r.rj_maintenance_zone_name, cur_r.rj_maintenance_zone_code);
end loop;
end fiber_transm_valid_data;

Not quite like that; IF is wrong. Have a look at this.
create or replace procedure fiber_transm_valid_data as
l_state_name table_of_states.rj_state_name%type;
begin
for cur_r in (select rj_span_id,
rj_maintenance_zone_name,
rj_maintenance_zone_code,
rj_state_name
from app_fttx.transmedia#sat
)
loop
select max(rj_state_name)
into l_state_name
from table_of_states
where rj_state_name = cur_r.rj_state_name
and rownum = 1;
if cur_r.rj_span_id > '0'
and cur_r.rj_maintenance_zone_name = 'aa'
and cur_r.rj_maintenance_zone_code = 'A123'
and l_state_name = 1
then
INSERT INTO VALID_TABLE
(span_id, maintenance_zone_name,rj_maintenance_zone_code)
values
(cur_r.rj_span_id, cur_r.rj_maintenance_zone_name, cur_r.rj_maintenance_zone_code);
else
INSERT INTO INVALID_TABLE
(span_id, maintenance_zone_name,rj_maintenance_zone_code)
values
(cur_r.rj_span_id, cur_r.rj_maintenance_zone_name, cur_r.rj_maintenance_zone_code);
end if;
end loop;
end fiber_transm_valid_data;

Related

Check if Exists PLS-00405: subquery not allowed in this context

I have cursor it selects from TableA then Fetch Loop that inserts into TableB.
I want to check if the value already exists in the TableB.
If it exists then I want to skip the insert.
create or replace
PROCEDURE DAILY_RPT (
v_start IN DATE,
v_end IN DATE)
IS
ao_out_no out_pair.out_no%type;
cursor get is
SELECT ao_out_no from tableA;
BEGIN
open get;
LOOP
fetch get into ao_out_no;
EXIT WHEN get%NOTFOUND;
if (ao_out_no = (select out_no from TableA where out_no = ao_out_no) THEN
--DO NOTHING
else
INSERT INTO TABLEB(OUT_NO) VALUES (ao_out_no);
end if;
END LOOP;
close get;
END;
I used IF CONDITION however, I used variable into if condition & I am getting below.
PLS-00405: subquery not allowed in this context
if (ao_out_no = (select out_no from TableA where out_no = ao_out_no) THEN
You don't need cursor or PL/SQL at all:
INSERT INTO TABLEB(OUT_NO)
SELECT ao_out_no
FROM tableA ta
WHERE ... -- filtering rows
AND NOT EXISTS (SELECT * From TableB tb WHERE tb.OUT_NO = ta.ao_out_no);
Use the following :
for i in (
select out_no from TableA where out_no
)
loop
if i.out_no = ao_out_no
then
-- DO NOTHING
else
...
or
create a new variable named x, and then assign a value to it by
select out_no into x from TableA where out_no = ao_out_no;
and check returning value for x.
With corrected syntax, it would be something like this:
create or replace procedure daily_rpt
( v_start in date
, v_end in date )
as
begin
for r in (
select ao_out_no, 0 as exists_check
from tablea
)
loop
select count(*) into exists_check
from tablea
where out_no = r.ao_out_no
and rownum = 1;
if r.exists_check > 0 then
--DO NOTHING
else
insert into tableb (out_no) values (r.ao_out_no);
end if;
end loop;
end;
However, it's inefficient to query all of the rows and then do an additional lookup for each row to decide whether you want to use it, as SQL can do that kind of thing for you. So version 2 might be something like:
create or replace procedure daily_rpt
( v_start in date
, v_end in date )
as
begin
for r in (
select ao_out_no
from tablea
where not exists
( select count(*)
from tablea
where out_no = r.ao_out_no
and rownum = 1 )
)
loop
insert into tableb (out_no) values (r.ao_out_no);
end loop;
end;
at which point you might replace the whole loop with an insert ... where not exists (...) statement.

ORA-01403: no data found -- Exception handling not working

BEGIN
FOR v_LoadRec IN c_Load LOOP
SELECT count(1) INTO v_NO_OF_DAYS_RESP
from DIM_DATE
where DIM_DATE.TRADING_DAY_FLAG = 'Y' and
DIM_DATE_KEY <= TO_NUMBER(TO_CHAR(v_LoadRec.RESPONSE_DATE,'YYYYMMDD')) and
DIM_DATE_KEY >= TO_NUMBER(TO_CHAR(v_LoadRec.OPEN_DATE, 'YYYYMMDD'))
group by v_LoadRec.CALL_NUMBER;
IF SQL%NOTFOUND THEN
v_NO_OF_DAYS_RESP :='';
END IF;
SELECT count(1) INTO v_NO_OF_DAYS_RESO
from DIM_DATE
where DIM_DATE.TRADING_DAY_FLAG = 'Y' and
DIM_DATE_KEY <= TO_NUMBER(TO_CHAR(v_LoadRec.RESOLVE_DATE,'YYYYMMDD')) and
DIM_DATE_KEY >= TO_NUMBER(TO_CHAR(v_LoadRec.OPEN_DATE, 'YYYYMMDD'))
group by v_LoadRec.CALL_NUMBER;
IF SQL%NOTFOUND THEN
v_NO_OF_DAYS_RESO :='';
END IF;
END LOOP;
I have this block of SQL in my update procedure which gathers the count of trading days for each record and then inserts it into an integer variable named "v_NO_OF_DAYS_RESP" e.g. count of days between the open and response date of a call.
This works well except for when there is a null "RESPONSE_DATE" where it fails with the "ORA-01403: no data found" error. I understand why it's failing (because it of course has no record to insert) but I can't seem to figure out a way to get around it.
In these circumstances where the "RESPONSE_DATE" is found to be NULL, I would like the "v_NO_OF_DAYS_RESP" var to be set to NULL too (or even somehow have the SQL statement nested within an "IF" to possibly completely avoid running the calculation (SQL statement) when the "RESPONSE_DATE" is NULL).
*To put it really simple, I want the following:.. If the call does not yet have a response date, either don't run the SQL statement (calculation) or just set the var to Null
Any ideas or suggestions would be greatly appreciated.
Thanks - Kelvin
Handling exception will solve your problem:
BEGIN
FOR v_LoadRec IN c_Load LOOP
SELECT count(1) INTO v_NO_OF_DAYS_RESP
from DIM_DATE
where DIM_DATE.TRADING_DAY_FLAG = 'Y' and
DIM_DATE_KEY <= TO_NUMBER(TO_CHAR(v_LoadRec.RESPONSE_DATE,'YYYYMMDD')) and
DIM_DATE_KEY >= TO_NUMBER(TO_CHAR(v_LoadRec.OPEN_DATE, 'YYYYMMDD'))
group by v_LoadRec.CALL_NUMBER;
IF SQL%NOTFOUND THEN
v_NO_OF_DAYS_RESP :='';
END IF;
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_NO_OF_DAYS_RESP :='';
END;
if (v_LoadRec.RESPONSE_DATE) is null Then
v_NO_OF_DAYS_RESP:='';
else
SELECT count(1) INTO v_NO_OF_DAYS_RESP
from DIM_DATE
where DIM_DATE.TRADING_DAY_FLAG = 'Y' and
DIM_DATE_KEY <= TO_NUMBER(TO_CHAR(v_LoadRec.RESPONSE_DATE, 'YYYYMMDD')) and
DIM_DATE_KEY >= TO_NUMBER(TO_CHAR(v_LoadRec.OPEN_DATE, 'YYYYMMDD'))
group by v_LoadRec.CALL_NUMBER;
IF SQL%NOTFOUND THEN
v_NO_OF_DAYS_RESP :='';
END IF;
end if;
Get the count of records in SELECT query. Then you can validate (count=0 or not).You can try like this.
result VARCHAR2(100);
result_count NUMBER;
BEGIN
SELECT count(<COLUMN_NAME>) INTO result_count FROM <TABLE_NAME> where empid = 12;
IF result_coun = 0 THEN
result := 'Value does not exist in the reference table';
END IF;
END;

How to fetch cursor value with %ROWTYPE

i make a procedure as shown below i want to fetch cursor values and extract these values from other loop tell me best way here is my code
CREATE OR REPLACE PROCEDURE TEST (P_EMP_ID NUMBER,
TRIGER_BY VARCHAR2)
AS
CURSOR TO_HOD
IS
SELECT EMP.EMPLOYEE_CODE,
EMP.EMP_NAME,
APR.LEFT_DT,
APR.RESIGN_TYPE
FROM FSC_APPROVAL APR, CHR_ALL_EMPLOYEE_BI_V EMP
WHERE APR.HOD_APPR = 'Y'
AND APR.ZONE_HD_APPR IS NULL
AND EMP.EMPLOYEE_ID = APR.EMP_ID;
CURSOR TO_ZONE
IS
SELECT EMP.EMPLOYEE_CODE,
EMP.EMP_NAME,
APR.LEFT_DT,
APR.RESIGN_TYPE
FROM FSC_APPROVAL APR, CHR_ALL_EMPLOYEE_BI_V EMP
WHERE APR.HOD_APPR = 'Y'
AND APR.ZONE_HD_APPR = 'Y'
AND APR.TIM_OFC_APPR IS NULL
AND EMP.EMPLOYEE_ID = APR.EMP_ID;
CUR_VAL TO_HOD%ROWTYPE;
CUR_VAL_FOR_LOOP TO_HOD%ROWTYPE;
Here procedure begin
BEGIN
IF TRIGER_BY = 'HOD'
THEN
OPEN TO_HOD;
LOOP
FETCH TO_HOD INTO CUR_VAL;
EXIT WHEN TO_HOD%NOTFOUND;
END LOOP;
ELSIF TRIGER_BY = 'ZONE'
THEN
OPEN TO_ZONE;
LOOP
FETCH TO_ZONE INTO CUR_VAL;
EXIT WHEN TO_ZONE%NOTFOUND;
END LOOP;
END IF;
in above code just fetch my data and put in cur_val that was %rowtype
after that i fetch these values in new loop but its not make sense and show error PLS-00456: item 'CUR_VAL' is not a cursor
LOOP
***FETCH CUR_VAL INTO CUR_VAL_FOR_LOOP;***
DBMS_OUTPUT.PUT_LINE (CUR_VAL_FOR_LOOP.EMPLOYEE_CODE);
END LOOP;
END;
/
i am face error on this line FETCH CUR_VAL INTO CUR_VAL_FOR_LOOP;
please guide me how i make this procedure as i desire if you have better option then i warmly welcome if you have further query about my Question then i will here to describe you
Why do you use two variables? You can do it shorter (not tested):
CURSOR TO_ALL(hd APR.ZONE_HD_APPR%TYPE) IS
SELECT EMP.EMPLOYEE_CODE,
EMP.EMP_NAME,
APR.LEFT_DT,
APR.RESIGN_TYPE
FROM FSC_APPROVAL APR,
JOIN CHR_ALL_EMPLOYEE_BI_V EMP ON EMP.EMPLOYEE_ID = APR.EMP_ID
WHERE APR.HOD_APPR = 'Y'
AND NVL(APR.ZONE_HD_APPR, 'NULL') = NVL(hd, 'NULL')
AND EMP.EMPLOYEE_ID = APR.EMP_ID;
CUR_VAL TO_ALL%ROWTYPE;
BEGIN
OPEN TO_ALL(CASE TRIGER_BY WHEN 'HOD' THEN 'NULL' ELSE 'Y');
LOOP
FETCH TO_ALL INTO CUR_VAL;
...
EXIT WHEN TO_ALL%NOTFOUND;
END LOOP;
END;

How to stop repeating of row using %type and cursor

i make a procedure as shown below i want to fetch cursor values and extract these values in a variables and extract these variable in a new loop but issue same row is repeated
CREATE OR REPLACE PROCEDURE FSC.TEST (TRIGER_BY VARCHAR2)
AS
CURSOR TO_HOD
IS
SELECT EMP.EMPLOYEE_CODE,
EMP.EMP_NAME
--APR.LEFT_DT,
-- APR.RESIGN_TYPE
FROM FSC_APPROVAL APR, CHR_ALL_EMPLOYEE_BI_V EMP
WHERE APR.HOD_APPR = 'Y'
AND APR.ZONE_HD_APPR IS NULL
AND EMP.EMPLOYEE_ID = APR.EMP_ID;
CURSOR TO_ZONE
IS
SELECT EMP.EMPLOYEE_CODE,
EMP.EMP_NAME
-- APR.LEFT_DT,
-- APR.RESIGN_TYPE
FROM FSC_APPROVAL APR, CHR_ALL_EMPLOYEE_BI_V EMP
WHERE APR.HOD_APPR = 'Y'
AND APR.ZONE_HD_APPR = 'Y'
AND APR.TIM_OFC_APPR IS NULL
AND EMP.EMPLOYEE_ID = APR.EMP_ID;
emp_code CHR_ALL_EMPLOYEE_BI_V.EMPLOYEE_CODE%type;
emp_name CHR_ALL_EMPLOYEE_BI_V.EMP_NAME%type;
BEGIN
IF TRIGER_BY = 'HOD'
THEN
OPEN TO_HOD;
LOOP
FETCH TO_HOD INTO emp_code,emp_name;
EXIT WHEN TO_HOD%NOTFOUND;
counter:=TO_HOD%ROWCOUNT;
END LOOP;
ELSIF TRIGER_BY = 'ZONE'
THEN
OPEN TO_ZONE;
LOOP
FETCH TO_ZONE INTO emp_code,emp_name;
EXIT WHEN TO_ZONE%NOTFOUND;
counter:=TO_ZONE%ROWCOUNT;
END LOOP;
END IF;
here i extract the data that i store in loop in above code
this loop extract the data
for i in 1..counter loop
DBMS_OUTPUT.PUT_LINE (emp_code||' '||emp_name);
--EXIT WHEN CUR_VAL is null;
end loop;
END;
/
but same row is repeated
emp_code and emp_name are scalars. That is, they only store one value. Each time you fetch data into them, you are overwriting the prior value. If you are trying to print the data at the end, emp_code and emp_name will only have the last values that were fetched and you'll repeat that many times.
Why are you using explicit cursors in the first place (which, incidentally, you've failed to close)? If, as I'm guessing, you're new to PL/SQL, you're better off using implicit cursors.
IF TRIGER_BY = 'HOD'
THEN
for rec in to_hod
loop
dbms_output.put_line( rec.employee_code || ' ' || rec.emp_name );
end loop;
ELSIF triger_by = 'ZONE'
THEN
for rec in to_zone
loop
dbms_output.put_line( rec.employee_code || ' ' || rec.emp_name );
end loop;
END IF;
Now, you could use implicit cursors, declare local collection types rather than local scalar variables, do a bulk collect from the cursor into that collection type, and then iterate through the collection in a subsequent step. But I am guessing that is more than you really want to do.

Oracle PL/SQL Trigger Error

I'm trying to get a trigger to update a reportnum and suffix and be compatible with Coldfusion ORM. To make this work for tables with a single key I've used the first part of the example below. In this table I need it to update the suffix to the next value if the report number is given.
CREATE TABLE tb1 ( reportnum NUMBER, suffix NUMBER );
CREATE SEQUENCE seq1 START WITH 1;
CREATE OR REPLACE TRIGGER "TRG1_TB1" BEFORE INSERT ON
tb1 FOR EACH ROW
BEGIN
IF :NEW.reportnum IS NULL THEN
SELECT seq1.NEXTVAL INTO :NEW.reportnum FROM dual;
ELSIF :NEW.REPORTNUM = '' THEN
SELECT seq1.NEXTVAL INTO :NEW.reportnum FROM dual;
ELSIF :NEW.suffix = '' THEN
SELECT MAX(suffix)+1 INTO :NEW.suffix FROM tb1 WHERE reportnum = :NEW.reportnum
ELSIF :NEW.suffix = NULL THEN
SELECT MAX(suffix)+1 INTO :NEW.suffix FROM tb1 WHERE reportnum = :NEW.reportnum
END IF;
END;
The error that I'm getting is that they command is not properly ended.
add ; at the end of your suffix queries
ELSIF :NEW.suffix = '' THEN
SELECT MAX(suffix)+1 INTO :NEW.suffix
FROM tb1 WHERE reportnum = :NEW.reportnum;
ELSIF :NEW.suffix = NULL THEN
SELECT MAX(suffix)+1 INTO :NEW.suffix
FROM tb1 WHERE reportnum = :NEW.reportnum;
You can also reduce number of if statements for both by doing this:
For example:
IF coalesce(:NEW.reportnum,-1) = -1 THEN
SELECT seq1.NEXTVAL INTO :NEW.reportnum FROM dual;
ELSIF coalesce(:NEW.suffix,-1) = -1 THEN
SELECT MAX(suffix)+1 INTO :NEW.suffix
FROM tb1 WHERE reportnum = :NEW.reportnum;
END IF;
You are not getting the Oracle PL/SQL Trigger Error, it is the syntax error.
try this:
CREATE TABLE tb1 ( reportnum NUMBER, suffix NUMBER );
CREATE SEQUENCE seq1 START WITH 1;
CREATE OR REPLACE TRIGGER "TRG1_TB1" BEFORE INSERT ON
tb1 FOR EACH ROW
BEGIN
IF :NEW.reportnum IS NULL THEN
SELECT seq1.NEXTVAL INTO :NEW.reportnum FROM dual;
ELSIF :NEW.suffix is NULL THEN
SELECT MAX(suffix)+1 INTO :NEW.suffix FROM tb1 WHERE reportnum = :NEW.reportnum;
END IF;
END;

Resources