I have a cursor that I need to loop through and check a couple conditions. If the person's category is greater than 24, I need it to then see if the person also had a previous record in the table and change the value of the v_check variable if it meets the conditions. The problem is it is saying I can't use a query here. How could I pull this off?
[Error] Compilation (248: 39): PLS-00405: subquery not allowed in this context
IF v_category > 24 THEN
IF v_person_id = (
SELECT person_id
FROM mytable
WHERE category = 24
AND outcome IS NULL
AND person_id = v_person_id
) THEN v_check := 'NO PREV OUTCOME';
ELSIF v_person_id = (
SELECT person_id
FROM mytable
WHERE category = 24
AND outcome_date IS NULL
AND person_id = v_person_id
) THEN v_check := 'NO OUTCOME DATE';
ELSIF category = 24 THEN v_check := 'N/A';
END IF;
ELSE v_check := 'OK';
END IF;
Main problem is that you can't use a subquery that way; first find value(s) returned by the select statement(s), then use them in case.
Also, code you posted doesn't make much sense as
you use v_person_id as a variable (to store a value into) and - at the same time - in select's where clause
the first if checks whether v_category > 24, while the last elsif says that if v_category = 24 then 'N/A' - that's never going to happen.
Here's an example which show how to do it; it probably won't work because I don't know what exactly you want to do (because of notes I posted above), but I hope that it'll get you started.
declare
v_person_id number := some value
l_person_id number;
l_person_uid number;
begin
select person_id, person_uid
into l_person_id, l_person_uid
from mytable
where category = 24
and outcome is null
and person_id = v_person_id;
v_check = case when v_category > 24 and v_person_id = l_person_id then 'NO PREV OUTCOME'
when v_category > 24 and v_person_id = l_person_uid then 'NO OUTCOME DATE'
else 'N/A'
end;
end;
Related
I have a Validation beginner's question here:
I have a select list item, options:
Product
SKU
If the user selects the SKU option a new textfield Item is shown for the customer to write down the SKU number.
My validation then tries to prevent an invalid SKU to be inserted.
This is what I have so far:
declare
v_rows_approved_min number;
v_rows_approved_max number;
err varchar2(300);
begin
if :P8_PRODUCT_OR_SKU = 'SKU' -- THIS IS MY SELECT LIST ITEM
then
err := 'Not a valid SKU';
v_rows_approved_min := 1;
select count(*) into v_rows_approved_max from SKU_TABLE;
for cur_a in (select SKU from SKU_TABLE)
loop
exit when v_rows_approved_min > v_rows_approved_max;
if :P8_SKU = cur_a.SKU
then return err;
else null;
end if;
v_rows_approved_min := v_rows_approved_min + 1;
end loop;
else null;
end if;
end;
Not sure what's going on here, can anyone help please?
Thanks!
This code is overly complex. It checks if a page item value exists in a table and returns an error if a match is found. This is done with a loop with some additional logic to exit the loop with the number of iterations reaches the select count. That last logic is not needed. If a table contains 5 rows, then the loop will have 5 iterations. No need to do a SELECT count from the table (v_rows_approved_max) and then check every iteration if that number has not been reached yet...
Also, there is no RETURN statement if not match is found, so that is added at the end.
Here is an attempt at a rewrite:
DECLARE
---- not needed
-- v_rows_approved_min NUMBER;
-- v_rows_approved_max NUMBER;
err VARCHAR2(300) := 'Not a valid SKU';
BEGIN
IF :P8_PRODUCT_OR_SKU = 'SKU' -- THIS IS MY SELECT LIST ITEM
THEN
---- err can be defaulted in declaration
--err := 'Not a valid SKU';
--v_rows_approved_min := 1;
---- not needed see below
--SELECT COUNT(*) INTO v_rows_approved_max FROM sku_table;
FOR cur_a IN ( SELECT sku FROM sku_table ) LOOP
---- not needed. You're looping through the table, v_rows_approved_min will be > than v_rows_approved_max
--EXIT WHEN v_rows_approved_min > v_rows_approved_max;
IF :P8_SKU = cur_a.sku THEN
RETURN err;
---- not needed
-- ELSE
-- NULL;
END IF;
---- not needed
-- v_rows_approved_min := v_rows_approved_min + 1;
END LOOP;
---- not needed
-- ELSE
-- NULL;
END IF;
-- you need to return something whenever the function ends...
RETURN NULL;
END;
/
however...
This can be greatly simplified.
Create a validation of type "Rows returned"
Source:
SELECT
1
FROM
sku_table WHERE sku = :P8_SKU
Error Message: Not a valid SKU
Server Side condition (Type Item = Value): Item: P8_PRODUCT_OR_SKU; Value: SKU
This does exactly the same thing.
I have a cursor which inserts the valid data into valid table and invalid data into invalid table based on several criteria. Below is my cursor logic for the same.
create or replace PROCEDURE FIP_VAL_INV_DATA AS
l_state_name r4g_lb.mantainenceboundary_evw.jiostatename%type;
l_maint_zone_code r4g_lb.mantainenceboundary_evw.maintenancezonecode%type;
l_maint_zone_name r4g_lb.mantainenceboundary_evw.maintenancezonename%type;
l_state_code r4g_lb.mantainenceboundary_evw.jiostatecode%type;
begin
for cur_r in (select rj_span_id,
rj_maintenance_zone_name,
rj_maintenance_zone_code,
rj_state_name,
rj_network_category,
rj_network_type,
rj_construction_methodology,
inventory_status_code,
rj_route_name,
rj_intracity_link_id,
calculated_length
from app_fttx.transmedia#sat
where --rownum < 100 and
jumper_flag is null
)
loop
select max(jiostatename)
into l_state_name
from r4g_lb.mantainenceboundary_evw
where jiostatename = cur_r.rj_state_name
and rownum = 1;
--dbms_output.put_line('test');
select max(maintenancezonecode), max(maintenancezonename)
into l_maint_zone_code, l_maint_zone_name
from r4g_lb.mantainenceboundary_evw
where maintenancezonecode = cur_r.rj_maintenance_zone_code
and maintenancezonename = cur_r.rj_maintenance_zone_name
and rownum = 1;
if length(cur_r.rj_span_id) = '21'
and cur_r.inventory_status_code = 'IPL'
and regexp_like(cur_r.rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$')
and NVL(INSTR(cur_r.RJ_INTRACITY_LINK_ID, '_'), 1) > 0
and cur_r.rj_maintenance_zone_code = l_maint_zone_code
and cur_r.rj_maintenance_zone_name = l_maint_zone_name
and cur_r.rj_state_name = l_state_name
then
begin
INSERT INTO tbl_fiber_valid_trans_data
(span_id, maintenance_zone_name, maintenance_zone_code, r4g_state_name, inventory_status_code, network_category, network_type, construction_methodology, route_name,intracity_link_id, calculated_length, last_updated_by)
values
(cur_r.rj_span_id, cur_r.rj_maintenance_zone_name, cur_r.rj_maintenance_zone_code, cur_r.rj_state_name, cur_r.inventory_status_code, cur_r.rj_network_category, cur_r.rj_network_type, cur_r.rj_construction_methodology, cur_r.rj_route_name, cur_r.rj_intracity_link_id, cur_r.calculated_length, 'Test');
end;
elsif LENGTH(cur_r.rj_intracity_link_id) > 8
AND LENGTH(cur_r.rj_intracity_link_id) < 21
and cur_r.inventory_status_code = 'IPL'
and cur_r.rj_maintenance_zone_code = l_maint_zone_code
and cur_r.rj_maintenance_zone_name = l_maint_zone_name
and cur_r.rj_state_name = l_state_name
then
begin
INSERT INTO tbl_fiber_valid_trans_data
(span_id, maintenance_zone_name, maintenance_zone_code, r4g_state_name, inventory_status_code, network_category, network_type, construction_methodology, route_name,intracity_link_id, calculated_length, last_updated_by)
values
(cur_r.rj_span_id, cur_r.rj_maintenance_zone_name, cur_r.rj_maintenance_zone_code, cur_r.rj_state_name, cur_r.inventory_status_code, cur_r.rj_network_category, cur_r.rj_network_type, cur_r.rj_construction_methodology, cur_r.rj_route_name, cur_r.rj_intracity_link_id, cur_r.calculated_length, 'Test');
end;
else begin
INSERT INTO TBL_FIBER_INVALID_TRANS_DATA
(span_id, maintenance_zone_name, maintenance_zone_code, r4g_state_name, inventory_status_code, network_category, network_type, construction_methodology, route_name,intracity_link_id, calculated_length, last_updated_by, remarks)
values
(cur_r.rj_span_id, cur_r.rj_maintenance_zone_name, cur_r.rj_maintenance_zone_code, cur_r.rj_state_name, cur_r.inventory_status_code, cur_r.rj_network_category, cur_r.rj_network_type, cur_r.rj_construction_methodology, cur_r.rj_route_name, cur_r.rj_intracity_link_id, cur_r.calculated_length, 'Test', dynamic remarks based upon the error);
end;
end if;
end loop;
END FIP_VAL_INV_DATA;
So now what I want is, If one row is invalid and gets inserted into the invalid table i.e TBL_FIBER_INVALID_TRANS_DATA. I want also to insert the remarks for what reason the record is invalid.
For adding reason, i have several conditions mentioned above like,
if length(cur_r.rj_span_id) = '21' suppose the length is not equal to 21. We can add remarks as The length is not equal to 21 characters.
Like this we can add several remarks in remarks column of invalid table dynamically.
Please suggest how to achieve it.
UPDATE
There are several options you may choose. One is to create additional table which logs all errors you find. It has two columns: ID and ERR_CODE. You'd then have to search through source data set and insert rows into that table, e.g.
ERR_CODE = 1 = length not equal to 21
Then:
insert into errors (id, err_code)
select t.id, 1
from source_table t
where length(some_column) <> 21;
It allows you to store multiple errors for the same ID, and it'll be normalized.
Another option is to alter TBL_FIBER_INVALID_TRANS_DATA and add errors varchar2(100); you'd still have to find what's wrong and
insert one row per ID per error description (so, multiple rows per ID if it has many errors)
insert only one row per ID and concatenate error codes into the newly added column (so if ID contains errors 1, 8 and 12 it would contain e.g. 1/8/12). This is OK if there are only a few errors so you can see what's going on simply by looking at it, but - if there are more errors you capture, it becomes difficult to understand, it is not normalized and you'll have additional problems if you'd want to present all errors found on one ID
If I were you, I'd probably go with option #1 and additional table. Then it is easy to create report for end users (or yourself) by joining TBL_FIBER_INVALID_TRANS_DATA and ERRORS on same ID.
For each cursor record, define a variable l_invalid_reason. Perform each validation individually and, if one fails, write the appropriate message into l_invalid_reason.
Then, if l_invalid_reason is null, insert it into the "valid" table. Otherwise, insert into the "invalid" table, passing l_invalid_reason in for the remarks column. Here is an abridged version of your code that does this, with comments.
create or replace PROCEDURE FIP_VAL_INV_DATA AS
begin
-- Open your cursor loop
for cur_r in (select ... ) loop
declare
l_invalid_reason VARCHAR2(100);
begin
-- Do various select into commands to get extra data needed (e.g. l_state_name, l_maint_zone_code, and l_maint_zone_name
select max(jiostatename) into l_state_name...
...
...
-- Do each validation individually
-- Notice you are checking for INVALID conditions, not VALID ones, so the
-- logic is reversed from your posting and you may need to account for possible nulls,
-- as in some of the examples below.
if length(cur_r.rj_span_id) != 21 then
l_invalid_reason := 'Length is not 21 characters exactly';
else if nvl(cur_r_inventory_status_code,'XXX') != 'IPL' then
l_invalid_reason := 'Inventory status code is not IPL';
else if not regexp_like(cur_r.rj_span_id, 'SP(N|Q|R|S).*_(BU|MP)$') then
l_invalid_reason := 'Span ID does not match accepted format';
else if .... (additional validations) ...
end if;
-- Check to see whether there is an invalid reason
if l_invalid_reason is null then
-- insert into good table
else
-- insert into invalid table
INSERT INTO TBL_FIBER_INVALID_TRANS_DATA
(span_id,
maintenance_zone_name,
maintenance_zone_code,
...
remarks)
values
(cur_r.rj_span_id,
cur_r.rj_maintenance_zone_name,
cur_r.rj_maintenance_zone_code,
...
l_invalid_reason); -- put the PL/SQL variable holding the invalid reason into the INSERT statement
end if;
end;
end loop;
END FIP_VAL_INV_DATA;
I try to write a stored procedure so that the transaction number returns to 01 every day, but when I run it, all transaction numbers on that day to 01 don't increase.
then I add
and (V_JML_RECORD = 1) THEN
V_JML_RECORD: = V_JML_RECORD +1;
and when I run it, I get an ORA-01422 error occurs; is there an exact exact return on requested number of rows that can explain and provide a solution to my problem?
SELECT TRIM (NAMA), TRIM (KD_KTR) AS KDKTR
INTO V_NAMA, V_KDKTR
FROM D_PRS
WHERE TRIM (STB) = P_STB;
SELECT TO_CHAR (sysdate, 'MM')
INTO V_BLNSKR
from dual;
SELECT TO_CHAR (sysdate, 'DD')
INTO V_HRSKR
from dual;
SELECT COUNT(NOKAS)
INTO V_JML_RECORD
FROM (
SELECT NOKAS,TGKAS,KTRASL FROM D_MSTHEADER_UKERJA WHERE TGKAS IN(
SELECT MAX(TGKAS) FROM D_MSTHEADER_UKERJA WHERE KTRASL=V_KDKTR)
)
IF (V_BLNSKR = '02')
AND (V_HRSKR = '27') THEN
V_JML_RECORD := 1;
ELSIF (V_BLNSKR = '02')
AND (V_HRSKR = '27')
AND (V_JML_RECORD = 1) THEN
V_JML_RECORD := V_JML_RECORD +1;
ELSE
V_JML_RECORD := V_JML_RECORD +1;
END IF;
To immediately resolved your issue add the ROWNUM= 1 on query below, but the correct way is for you to check which is the correct row to get by examining the result of your original query. You only have to fetch a SINGLE ROW query when using INTO function.
SELECT TRIM (NAMA), TRIM (KD_KTR) AS KDKTR
INTO V_NAMA, V_KDKTR
FROM D_PRS
WHERE TRIM (STB) = P_STB AND ROWNM = 1;
Below is my procedure, takes 51 sec to execute, I want to return cursor only if one count is found, in case anything else will return message and cursor as null. In case cursor is found message as null..
I am first taking count by query and populating data by the same query later but only in case of count being one.
is their anyway in which this could be optimized in terms of time.?
create or replace PROCEDURE sp_cp_getcrnnofrmmobdob(P_MobileNo IN VARCHAR2,
P_Dob IN VARCHAR2,
p_Output out SYS_REFCURSOR,
p_Message OUT VARCHAR2) IS
vCRN Varchar2(50) := '';
vCustid varchar2(50) := '';
vMobno varchar2(50) := '';
vCustname varchar2(400) := '';
vCustDob varchar2(50) := '';
vcount int := 0;
BEGIN
p_Message := '';
OPEN p_Output FOR
select 1 from dual;
Select count(*)
into vcount
FROM (select distinct(C.fw_customer_id_c) crn,
C.Cust_Id_n custid,
c.customername custname,
c.dob custdob,
A.MOBILE mobileno
from FCH_CASTRANSACTION.NBFC_CUSTOMER_M C,
FCH_CASMASTER.nbfc_address_m A
where A.BPID = C.Cust_Id_n and
A.mobile = P_MobileNo and
TO_CHAR(TO_DATE(C.DOB, 'DD-MON-YY'),'DD-MON-YY')=TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY'));
if (vcount = 1) then
select B.crn,
B.custid,
B.mobileno,
B.custname,
B.custdob
into vCRN, vCustid, vMobno, vCustname, vCustDob
from (select distinct(C.fw_customer_id_c) crn,
C.Cust_Id_n custid,
c.customername custname,
c.dob custdob,
A.MOBILE mobileno
from FCH_CASTRANSACTION.NBFC_CUSTOMER_M C,
FCH_CASMASTER.nbfc_address_m A
where A.BPID = C.Cust_Id_n and
A.mobile = P_MobileNo and
TO_CHAR(TO_DATE(C.DOB, 'DD-MON-YY'),'DD-MON-YY')=TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY')) B;
if ((vCRN = '') OR (vCRN IS Null)) then
p_Message := 'No data found for entered details';
else
if ((vMobno <> P_MobileNo) OR (vMobno IS Null)) then
p_Message := 'Entered mobile number is not registered with us.Please contact customer care.';
else
if ((vCustDob <> TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY')) OR (vCustDob IS Null)) then
p_Message := 'Entered date of birth is not registered with us.Please contact customer care.';
else
OPEN p_Output FOR
select vCRN as "CrnNum", vCustid as "CustId", vMobno as "MobNo", vCustname as "CustName", vCustDob as "CustDob"
from dual;
End if;
End if;
End if;
else
p_Message := 'Inconsistent details for entered data found. Please contact customer care';
End if;
EXCEPTION
WHEN NO_DATA_FOUND THEN
p_Message := 'Unable to process your request.Please contact customer care.';
OPEN p_Output FOR
SELECT 1 FROM dual;
END;
Would really appreciate if someone can help.
You can just use one SELECT ... INTO ... and catch the exception TOO_MANY_ROWS.
'' and NULL are the same thing.
It will not return a row if the mobile number does not match (or is null) so that check is redundant.
Same for the date of birth check.
DISTINCT is NOT a function - it is a keyword that applies to all the rows.
You assigning a cursor to p_output twice. Also, some systems may not like that the function can return different numbers of columns to your cursor.
So, something like this:
create or replace PROCEDURE sp_cp_getcrnnofrmmobdob(
P_MobileNo IN VARCHAR2,
P_Dob IN VARCHAR2,
p_Output out SYS_REFCURSOR,
p_Message OUT VARCHAR2
)
IS
v_dob DATE := TO_DATE( p_dob, 'DD/MM/YYYY' );
vCRN FCH_CASTRANSACTION.NBFC_CUSTOMER_M.fw_customer_id_c%TYPE;
vCustid FCH_CASTRANSACTION.NBFC_CUSTOMER_M.Cust_Id_n%TYPE;
vMobno FCH_CASMASTER.nbfc_address_m.MOBILE%TYPE;
vCustname FCH_CASTRANSACTION.NBFC_CUSTOMER_M.customername%TYPE;
vCustDob FCH_CASTRANSACTION.NBFC_CUSTOMER_M.dob%TYPE;
BEGIN
p_Message := '';
select distinct
C.fw_customer_id_c,
C.Cust_Id_n,
c.customername,
c.dob,
A.MOBILE
into vCRN, vCustid, vMobno, vCustname, vCustDob
from FCH_CASTRANSACTION.NBFC_CUSTOMER_M C
INNER JOIN FCH_CASMASTER.nbfc_address_m A
ON ( A.BPID = C.Cust_Id_n )
WHERE A.mobile = P_MobileNo
AND TO_DATE( C.DOB, 'DD-MON-YY') = v_dob;
IF vCRN IS NULL THEN
p_Message := 'No data found for entered details';
OPEN p_Output FOR
select 1 from dual;
RETURN;
END IF;
OPEN p_Output FOR
select vCRN as "CrnNum", vCustid as "CustId", vMobno as "MobNo", vCustname as "CustName", vCustDob as "CustDob"
from dual;
EXCEPTION
WHEN NO_DATA_FOUND THEN
p_Message := 'Unable to process your request.Please contact customer care.';
OPEN p_Output FOR
SELECT 1 FROM dual;
WHEN TOO_MANY_ROWS THEN
p_Message := 'Inconsistent details for entered data found. Please contact customer care';
OPEN p_Output FOR
SELECT 1 FROM dual;
END;
Looking at TO_CHAR(TO_DATE(C.DOB, 'DD-MON-YY'),'DD-MON-YY')=TO_CHAR(TO_DATE(P_Dob,'DD/MM/YYYY'),'DD-MON-YY')) in both of your queries, I suggest.
Based on this logic, you are storing the date of birth (dob) as a string. It is a shame if you do, it should be in the database as a DATE.
You are converting the strings to a date and then back to a string. In Oracle, you can compare dates, so only convert from column to DATE, not again back to a string. Such as TO_DATE(column,'column format')=TO_DATE(variable,'variable format')
Or, better yet, for your data model, consider just converting the variable input date string to match the column string format. Like column = TO_CHAR(TO_DATE(variable, 'variable format'),'column format'). There are two possible advantages here. First, the conversion will only happen once for the supplied value, but the query never has to perform a function on the column value. If the table is big. Also, since there is no function to be performed on the column value, IF there is an index on this value, the optimizer can use it (although this may not help your example based on my guess on your data model). Performance improvement here would depend on how the dob is used by your query. If Oracle is lookup up records by mobile number, then filter by dob, it shouldn't make much difference, but if it goes the other way around, looking up by dob then filtering on mobile number, this could help immensely.
tl;dr Store dates as dates, compare dates as dates, avoid functions on the column values when possible
How can i update the old row value. I have used the :old variable but it does not work for me. Herein my code, if PID already exists in project table i.e. (varProjectExists = 1) then i update the payment term. Now, if payment term is null , i want to update with previous paymnent term value else new payment term that is flown
CREATE OR REPLACE TRIGGER TRIG_PROJECT_INSERT AFTER
INSERT ON TEST_SYN_EAI_PROJECT_IN FOR EACH row DECLARE varError_Msg NVARCHAR2(100);
varSucceeded NVARCHAR2(1);
varActive_YN NVARCHAR2(50);
varProject_Id INT;
varPid INT ;
varPay_Term VARCHAR2(200);
varPay_Term1 VARCHAR2(200);
varError_id INT;
varCurr_activeyn INT;
varProjectExists NUMBER;
BEGIN
varError_Msg := 'No error';
varSucceeded := 'Y';
varError_id := 0;
varProjectExists := 0;
varPID := :new.pid;
varPay_Term := :new.ATTRIBUTE1;
varPay_Term1 := :old.ATTRIBUTE1;
varActive_YN := :new.active_yn;
varProject_ID := :new.project_id;
IF (NVL(varProject_Id,0) = 0 ) THEN
varError_Msg := 'project ID can not be null';
varSucceeded := 'N';
varError_id := 1;
END IF;
SELECT
CASE
WHEN (UPPER(varActive_YN) = 'ACTIVE'
OR UPPER(varActive_YN) = 'Y')
THEN 1
WHEN (UPPER(varActive_YN) = 'INACTIVE'
OR UPPER(varActive_YN) = 'N')
THEN 0
ELSE varcurr_activeyn
END
INTO varActive_YN
FROM Dual;
SELECT COUNT(1)
INTO varProjectExists
FROM project
WHERE ProjectUniversalID = varProject_ID;
IF (varProjectExists = 1) THEN
UPDATE project
SET PID = varPID,
PAYMENTTERM =
CASE
WHEN varPay_Term = 'NULL'
THEN varPay_Term1
WHEN varPay_Term IS NULL
THEN varPay_Term1
ELSE varPay_Term
END
ELSE .....
The OLD pseudo-record refers to the pre-update state of the current row, and so is only meaningful during an update or delete operation. If you're inserting a new record there is no 'old' state to refer to.
From your comment you want to use the previous payment term value that already exists in the PROJECT table. That would't be available in OLD anyway as it isn't the table the trigger is against. If that is the case then you need to retrieve it at the same time you check that it exists. Something like:
CREATE OR REPLACE TRIGGER TRIG_PROJECT_INSERT
AFTER INSERT ON TEST_SYN_EAI_PROJECT_IN
FOR EACH ROW
DECLARE
...
BEGIN
...
varPay_Term := :new.ATTRIBUTE1;
-- varPay_Term1 := :old.ATTRIBUTE1; -- not valid
varActive_YN := :new.active_yn;
...
-- this doesn't need to select from dual, you can assign directly
varCurr_activeyn := CASE
WHEN (UPPER(varActive_YN) = 'ACTIVE'
OR UPPER(varActive_YN) = 'Y')
THEN 1
WHEN (UPPER(varActive_YN) = 'INACTIVE'
OR UPPER(varActive_YN) = 'N')
THEN 0
ELSE varCurr_activeyn
END CASE;
-- get the current term as you check if a record exists
SELECT COUNT(1), MAX(PAYMENTTERM)
INTO varProjectExists, varPay_Term1
FROM project
WHERE ProjectUniversalID = varProject_ID;
IF (varProjectExists = 1) THEN
UPDATE project
SET PID = varPID,
PAYMENTTERM =
CASE
WHEN varPay_Term = 'NULL'
THEN varPay_Term1
WHEN varPay_Term IS NULL
THEN varPay_Term1
ELSE varPay_Term
END
...
The MAX() is needed because you're already using an aggregate COUNT(), to avoid a no-data-found error if the ID doesn't exist. Assuming that ID is unique, it doesn't matter if you use MAX or MIN, the result is the same. (If it isn't unique then you'd have to decide which term value to use, so it's probably a safe assumption).