Plsql case is not reading properly from case - plsql

I need to read data row by row and update it based on the matching case.
My code is just reading ORBREFTND and inserting Refund from case , not reading other cases. What am i doing wrong.
DECLARE
v_tot_rows NUMBER (3);
v_eval ISG.SWR_CERT_TXN_MSG_TYPE.DESC_TX%TYPE;
CURSOR pltfm_msg_type_cur
IS
SELECT sctmt.PLTFM_MSG_TYPE_CD
FROM ISG.SWR_CERT_TXN_MSG_TYPE sctmt
JOIN ISG.FEATURE_VALUES ft_val
ON sctmt.SWR_CERT_FETR_VAL_ID = ft_val.FEATURE_VAL
JOIN ISG.FEATURE_CATEGORY ft_cat
ON ft_val.FEATURE_CAT = ft_cat.FEATURE_CAT
WHERE ft_cat.SHORT_DESCRIP = 'PLT'
AND ft_val.FEATURE_VALUE = 'Orbital';
BEGIN
FOR msg_code IN pltfm_msg_type_cur
LOOP
CASE msg_code.PLTFM_MSG_TYPE_CD
WHEN 'WAC'
THEN
v_eval := 'Authorization and Mark for Capture';
WHEN 'ORBAUTHCAP'
THEN
v_eval := 'Authorization Capture';
WHEN 'ORBREFTND'
THEN
v_eval := 'Refund';
END CASE;
UPDATE ISG.SWR_CERT_TXN_MSG_TYPE sctmt
SET sctmt.DESC_TX = v_eval;
END LOOP;
COMMIT;
v_tot_rows := SQL%ROWCOUNT;
/* Implicit Attribute %ROWCOUNT is used to find the number of rows affected by the update command */
DBMS_OUTPUT.PUT_LINE ('Total records updated : ' || v_tot_rows);
END;

You're missing a where-condition:
UPDATE ISG.SWR_CERT_TXN_MSG_TYPE sctmt
SET sctmt.DESC_TX = v_eval
WHERE sctmt.primarykey = msg_code.primarykey; -- This one is missing. Don't know your primary key..
Without the where you'll always set the value of the last cursor-object to all objects in your table ISG.SWR_CERT_TXN_MSG_TYPE.
You also need to select the key from your table:
CURSOR pltfm_msg_type_cur
IS
SELECT sctmt.PLTFM_MSG_TYPE_CD,
sctmt.PRIMARYKEY -- select key here
FROM ISG.SWR_CERT_TXN_MSG_TYPE sctmt
JOIN ISG.FEATURE_VALUES ft_val
ON sctmt.SWR_CERT_FETR_VAL_ID = ft_val.FEATURE_VAL
JOIN ISG.FEATURE_CATEGORY ft_cat
ON ft_val.FEATURE_CAT = ft_cat.FEATURE_CAT
WHERE ft_cat.SHORT_DESCRIP = 'PLT'
AND ft_val.FEATURE_VALUE = 'Orbital';

Related

After Insert Trigger sintax error - ORA-00922

There is a table which i want to update each row after inserted, when the user_type of my schedule table is a "superuser". I tried to convert the table/column names to "simplify", so some names may not make sense, it's ok.
The trigger code:
CREATE OR REPLACE TRIGGER "TR_UPT_SCHEDULE"
AFTER INSERT
ON SCHEDULE
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
DECLARE V_UserCode VARCHAR2(20);
BEGIN
--Find "super user" code.
SELECT UserTypeCode INTO V_UserCode FROM
(SELECT UL.User_Code,
UFT.UserTypeCode,
ROW_NUMBER() OVER (PARTITION BY UL.User_Code ORDER BY UF.UserTypeCode DESC) RN
FROM UserLogin UL
JOIN UserFunction UF
ON UL.User_Code = UF.User_Code
JOIN UserFuncType UFT
ON UFT.UserTypeCode = UF.UserTypeCode
WHERE UFT.FuncType = 'S'
) WHERE RN = 1;
EXCEPTION
WHEN NO_DATA_FOUND THEN
V_UserCode := NULL;
IF V_UserCode IS NOT NULL
THEN UPDATE SCHEDULE
SET :NEW.UserTypeCode = V_UserCode,
OrigScheType = :NEW.UserTypeCode
WHERE CompCode = :NEW.CompCode
AND UserTypeCode = :NEW.UserTypeCode
AND ScheOrigin = :NEW.ScheOrigin
AND ScheCode = :NEW.ScheCode;
END IF;
END;
When i try to create the trigger, is returned the fallowing error:
ORA-00922
I'm pretty sure the problem is the UPDATE part, where tried compare in the WHERE clause, the Schedule table keys to be sure of which row i'm updating(inserted), but i could not realize the problem.
In triggers, you don't update tablename set :new.columnname = some value, you directly assign values to :new.columnname using PL/SQL assignments or select into. Therefore, from a syntax point of view, the final update should be replaced with something like:
:new.usertypecode := v_usercode;
:new.origschetype := v_usercode;
(I am assuming the update is only intended to apply to the current row. If the idea is to update multiple rows in the triggering table, you can't do that in a row-level trigger.)
However, this logic doesn't look like it will work:
exception
when no_data_found then
v_usercode := null;
if v_usercode is not null then
v_usercode has to be null at this point, so you don't have a value to set :new.usertypecode to, and I'm not sure what you want the trigger to do.

Forms 6i if record exists then update

I need to create select statement in post_insert trigger. Is it possible if yes then how?
I want to check another table records if it exists then it will update it otherwise insert as new record. Please help.
My block code is that i want to run
DECLARE
EXSIST_TYPE varchar2(50);
EXSIST_NAME varchar2(50);
EXSIST_COMPANY VARCHAR2(100);
BEGIN
SELECT PRO_TYPE, PRO_NAME, COMPANY_NAME INTO EXSIST_TYPE, EXSIST_NAME ,EXSIST_COMPANY FROM STOCK;
IF
:PURCHASE_DETAIL.PRO_TYPE <> EXSIST_TYPE AND
:PURCHASE_DETAIL.PRO_NAME <> EXSIST_NAME AND
:PURCHASE_DETAIL.COMPANY_NAME <> EXSIST_COMPANY THEN*/
IF
:PURCHASE.RADIO_TYPE = 'PURCHASE' THEN
INSERT INTO STOCK(
PRO_TYPE ,
PRO_NAME ,
COMPANY_NAME ,
QUANTITY ,
PURCHASE_RATE,
SALE_RATE ,
RACK_NUM
)
VALUES
(
:PURCHASE_DETAIL.PRO_TYPE,
:PURCHASE_DETAIL.PRO_NAME,
:PURCHASE_DETAIL.COMPANY_NAME,
:PURCHASE_DETAIL.QUANTITY,
:PURCHASE_DETAIL.PRICE,
:PURCHASE_DETAIL.SALE_PRICE,
:PURCHASE_DETAIL.RACK_NUM
);
END IF;
ELSIF
:PURCHASE_DETAIL.PRO_TYPE = EXSIST_TYPE AND
:PURCHASE_DETAIL.PRO_NAME = EXSIST_NAME AND
:PURCHASE_DETAIL.COMPANY_NAME = EXSIST_NAME THEN
IF
:PURCHASE.RADIO_TYPE = 'PURCHASE' THEN
UPDATE STOCK SET
STOCK.QUANTITY = STOCK.QUANTITY+:PURCHASE_DETAIL.QUANTITY
WHERE
STOCK.PRO_TYPE = :PURCHASE_DETAIL.PRO_TYPE AND
STOCK.PRO_NAME = :PURCHASE_DETAIL.PRO_NAME AND
STOCK.COMPANY_NAME= :PURCHASE_DETAIL.COMPANY_NAME;
ELSIF
:PURCHASE.RADIO_TYPE = 'PRCH_RETURN' THEN
UPDATE STOCK SET
STOCK.QUANTITY = STOCK.QUANTITY-:PURCHASE_DETAIL.QUANTITY
WHERE
STOCK.PRO_TYPE = :PURCHASE_DETAIL.PRO_TYPE AND
STOCK.PRO_NAME = :PURCHASE_DETAIL.PRO_NAME AND
STOCK.COMPANY_NAME = :PURCHASE_DETAIL.COMPANY_NAME;
END IF;
END IF;
END;
You never said what happened when you ran that code.
Anyway: requirement you mentioned ("if it exists then it will update it otherwise insert") looks like an excellent candidate for a MERGE statement (also called upsert, as a combination of UPdate and inSERT).
As Forms 6i is an old piece of software, I'm pretty much sure that MERGE can't directly be used there. However, if the underlying database is at least 9i, MERGE will work - create a stored procedure that contains MERGE, and pass form items' values as parameters.
Here's an example (taken from here; have a look for more examples. I'm lazy to create my own code):
MERGE INTO employees e
USING hr_records h
ON (e.id = h.emp_id)
WHEN MATCHED THEN
UPDATE SET e.address = h.address
WHEN NOT MATCHED THEN
INSERT (id, address)
VALUES (h.emp_id, h.address);

How to use current cursor value in Select query with in procedure

I am trying to use c_msisdn value in cursor for select query but it gives error of No data found, However if I supply value myself like WHERE MSISDN = '315XXX' instead of WHERE MSISDN = c_msisdn result is returned. How can I use cursor value inside select.
DECLARE
c_msisdn SSM_SMSCDATA.MSISDN%type;
c_status SSM_SMSCDATA.STATUS%type;
c_promo_id SSM_SMSCDATA.PROMO_ID%type;
view_all_status char(50) := '';
unsub_all_status char(50) := '';
services_subscribed char(400) := '';
CURSOR c_smscdata is SELECT MSISDN, STATUS, PROMO_ID FROM SSM_SMSCDATA;
BEGIN
OPEN c_smscdata;
LOOP
FETCH c_smscdata into c_msisdn, c_status, c_promo_id;
SELECT SUBSCRIPTION_ID into services_subscribed FROM (SELECT LISTAGG(SUBSCRIPTION_ID, '-') WITHIN GROUP (ORDER BY MSISDN) AS SUBSCRIPTION_ID
FROM SINGLESUBSCRIPTION
WHERE MSISDN = c_msisdn
GROUP BY MSISDN);
IF c_promo_id = '2' THEN
view_all_status := 'View All';
ELSE view_all_status := 'Unsub All';
END IF;
IF c_status = 3 THEN
unsub_all_status := 'View Successful';
ELSE unsub_all_status := 'Unsuccessful';
END IF;
INSERT INTO SSM_DAILY_REPORT (msisdn,view_all,unsub_all,SERVICES)
VALUES (c_msisdn,view_all_status,unsub_all_status,services_subscribed);
--dbms_output.put_line(c_msisdn || ' ' || c_status || ' ' || c_promo_id);
EXIT
WHEN c_smscdata%notfound;
END LOOP;
CLOSE c_smscdata;
END;
The most likely reason why you're getting the NO_DATA_FOUND exception is because you have msisdn values in your ssm_smscdata table that aren't present in your singlesubscription table.
If I were you, I wouldn't bother using a cursor for loop. Instead, I'd do it all in a single INSERT statement, like so:
INSERT INTO ssm_daily_report (msisdn, view_all, unsub_all, services)
SELECT scs.msisdn,
CASE WHEN scs.promo_id = '2' THEN 'View All';
ELSE 'Unsub All'
END view_all_status,
CASE WHEN scs.status = 3 THEN 'View Successful';
ELSE 'Unsuccessful'
END unsub_all_status,
sss.services_subscribed
FROM ssmsmscdata scs
INNER JOIN (SELECT msisdn,
LISTAGG(subscription_id, '-') WITHIN GROUP (ORDER BY msisdn) AS services_subscribed
FROM singlesubscription
GROUP BY msisdn) sss ON sss.msisdn = scs.msisdn;
That way, you avoid reinventing the nested loop join (freeing up Oracle to choose the join type it thinks is best to use, which may or may not be nested loops). You also avoid all the context switching and row-by-row processing that your cursor loop involves, and you get Oracle to do all the work in one fell swoop.
Also, by doing the inner join, you avoid the thorny issue of rows that appear in the ssm_smscdata table but not the singlesubscription, as those rows won't be returned. Should you need those rows to be returned as well, you would need to convert the INNER JOIN in the query above into an OUTER JOIN.

How to stop updating null values in oracle

I have a sql procedure which perfectly works. please find it below.
declare
cid number;
cadd number;
ctras number;
pr varchar(2);
vad number;
cursor c1 IS
select ac_tras, cust_id, cust_addr from customer_master;
cursor c2 IS
select pr_adr from customer_address where cust_id = cid and cust_addr = cadd;
BEGIN
open c1;
LOOP
fetch c1 into ctras, cid, cadd;
EXIT WHEN C1%NOTFOUND;
OPEN c2;
LOOP
fetch c2 into pr;
if pr='Y'
THEN EXIT ;
ELSE
UPDATE customer_master
set cust_addr = (select cust_addr from customer_address where pr_adr = 'Y' and cust_id = cid) where ac_tras = ctras;
END IF;
EXIT WHEN C2%NOTFOUND;
END LOOP;
Close C2;
END LOOP;
CLOSE C1;
END;
Everything works fine. The problem is, The update statement updates null if the sub query returns null. How to avoid this.
If the subquery doesn't find a matching row then the master table will be updated with null, because ther eis no filter to stop that. A common way to avoid that is to check that a matching row does exist:
UPDATE customer_master
set cust_addr = (
select cust_addr from customer_address
where pr_adr = 'Y' and cust_id = cid)
where ac_tras = ctras
and exists (
select cust_addr from customer_address
where pr_adr = 'Y' and cust_id = cid)
;
It doesn't really matter which column name you use in the exists clause; some people prefer to use select * or select null but it seems to be a matter of taste really (unless you specify a column you aren't going to be using later and which can't be retrieved from an index you're using anyway, which could force an otherwise unnecessary table row lookup).
You could also do a merge. And has been pointed out several times now, you don't need cursors or any PL/SQL to do this.

How i can pass column names from variables in plsql update statement

DECLARE
v_name A.TRANSACTION_TYPE%TYPE :='SALARY';
v_salary A.SALARY%TYPE := 1000;
BEGIN
update A set v_name= v_salary where EMPID = 517;
-- PL/SQL: ORA-00904: "v_name": invalid identifier
--update A set SALARY = 1000 where EMPID = 517;
END;
/
My idea is to update table columns , but these column names are stored in variable. Is there any way to pass column names from variable ? Is there any options apart from Execute Immediate
Not sure if this will work in your situation, but I've written solutions where I wrote a script in SQLPlus and it "wrote" (using dbms_output.put_line or even just prompt) another script that did queries, and the columns/tables in those queries was determined by the logic in the SQLPlus script. Then I would execute as a script the output from my first script, and it would execute dynamically generated queries without ever needing execute immediate.
The following idea may work for multiple columns that are typed the same... As written, it will update all columns every time for a given record, but only the column specified by v_name will be changed to the value set in v_value; the other columns are simply updated to their existing value. The idea can be played with using DECODE, NVL or other similar conditional operators.
declare
v_name varchar2(20):= 'SAL';
v_value emptest.sal%TYPE := 5000;
begin
update emptest
set sal = ( select case when v_name = 'SAL' then v_value else sal end from dual),
comm = ( select case when v_name = 'COMM' then v_value else comm end from dual)
where empno = 7369;
commit;
end;

Resources