Multiple Update statements running slow in SQL Stored procedure - performance

Please refer to the below SQL commands which is a part of the stored procedure. The stored procedure creates a temporary table named #TREPORT and then I perform following multiple updates on SODATE column.
The temporary table (#TREPORT) has about 1 million records and below statements are making performance slower. How can I improve it further?
#SDATE and #EDATE are parameters which is starting date and ending date.
Thanks in advance.
UPDATE #TREPORT SET
SODATE = '1900-01-01 00:00:00.000' where #TREPORT.SODATE is NULL
UPDATE #TREPORT SET
SODATE = (SELECT TOP 1 docdate from SO200
where SO200.NUMBORIG = #TREPORT.SOPNr
AND SO200.SOTYPE = '3'
-- AND
--DOCDATE is not null and DOCDATE >= '' +CONVERT(varchar(10),#SDATE,101) +''
-- and DOCDATE <= '' +CONVERT(varchar(10),#EDATE,101) +''
)
where #TREPORT.SODATE = '1900-01-01 00:00:00.000' or #TREPORT.SODATE is NULL
UPDATE #TREPORT SET
SODATE = (SELECT TOP 1 docdate from SO100
where SO100.NUMBORIG = #TREPORT.SOPNr
AND SO100.SOTYPE = '3'
-- AND
--DOCDATE is not null and DOCDATE >= '' +CONVERT(varchar(10),#SDATE,101) +''
-- and DOCDATE is not null and DOCDATE <= '' +CONVERT(varchar(10),#EDATE,101) +''
)
where #TREPORT.SODATE = '1900-01-01 00:00:00.000' or #TREPORT.SODATE is NULL
UPDATE #TREPORT SET
RowValue = 'C' where
(#TREPORT.SODATE < '' +CONVERT(varchar(10),#SDATE,101) +''
or #TREPORT.SODATE > '' +CONVERT(varchar(10),#EDATE,101) +'')
UPDATE #TREPORT SET
RowValue = 'D' where #TREPORT.SODATE = '1900-01-01 00:00:00.000'
or #TREPORT.SODATE is NULL

Large updates are best performed in batches. See the solution here:
http://www.sqlusa.com/bestpractices/largeupdate/
As for combining your updates, your first update is completely superfluous because you're replacing NULL with a default value, and the other updates replace "NULL or {the default value}", so you could have just skipped the first one completely.
The other 4 updates could be combined into one with a CASE statement.
UPDATE #TREPORT SET SODATE=CASE
WHEN EXISTS(SELECT * from SO200 where SO200.NUMBORIG = #TREPORT.SOPNr AND SO200.SOTYPE = '3')
THEN (SELECT TOP 1 docdate from SO200
where SO200.NUMBORIG = #TREPORT.SOPNr
AND SO200.SOTYPE = '3')
WHEN EXISTS(SELECT * from SO100 where SO100.NUMBORIG = #TREPORT.SOPNr AND SO100.SOTYPE = '3')
THEN (SELECT TOP 1 docdate from SO100
where SO100.NUMBORIG = #TREPORT.SOPNr
AND SO100.SOTYPE = '3')
ELSE '1900-01-01 00:00:00.000'
END
, RowValue=CASE
WHEN (#TREPORT.SODATE < '' +CONVERT(varchar(10),#SDATE,101) +''
or #TREPORT.SODATE > '' +CONVERT(varchar(10),#EDATE,101) +'')
THEN 'C'
ELSE 'D'
END
where #TREPORT.SODATE = '1900-01-01 00:00:00.000' or #TREPORT.SODATE is NULL

Related

Unexpected NULL in multi-column correlated update

I want to run a multi-column correlated update of this kind:
UPDATE t1 t1_alias
SET (table_name, tablespace_name) = (
SELECT table_name, tablespace_name
FROM t2 t2_alias
WHERE t1_alias.table_name = t2_alias.table_name
);
But my attempt:
update customer up
set (customer_name, account, active) = (
select tmp.name, tmp.account, case when tmp.active = 'Yes' then 1 else 0 end
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
);
... throws:
ORA-01407: cannot update ("FOO"."CUSTOMER"."CUSTOMER_NAME") to NULL
The source table customer_temp has no null values so I must be getting matches wrong. What is my error or misconception?
Presumably, there are some rows in the target table that have no match in the subquery.
You can avoid this with by adding an exists condition that filters out "unmatched" rows:
update customer up
set (customer_name, account, active) = (
select tmp.name, tmp.account, case when tmp.active = 'Yes' then 1 else 0 end
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
)
where exists (
select 1
from customer_temp tmp
where up.agent = substr(tmp.agent, -4) and up.customer_code = tmp.code
);

If Else logic converting to Select case - Oracle

IF inputVariable = '0'
THEN
DELETE existingTemptable
WHERE status != 999;
ELSE
IF inputVariable = '1'
THEN
DELETE existingTemptable
WHERE status = 999;
ELSE
DELETE existingTemptable
WHERE status != 999
AND date < utils.dateadd('MONTH', -6, SYSTIMESTAMP);
END IF;
END IF;
This If logic is present on a temp table and I have to remove the temp table and make it only select query , so approached with WITH CTE but stuck in the below
what should be in the where clause
with existingTemptable as
(
//got the temp table here
), myTable as
(
Select * from existingTemptable
**where
status = CASE WHEN inputVariable = '0' THEN 999
WHEN inputVariable != '0' AND inputVariable != '1' THEN 999
ELSE status
END**
)Select * from myTable
What to put in WHERE clause so that it mimics the If logic above
You have to be careful if inputVariable or status (or both) may be null. The rest is a direct application of logical rules one learns (or should learn) in middle school.
select *
from existingTemptable
where inputVariable = '0' and (status = 999 or status is null)
or
inputVariable = '1' and (status != 999 or status is null)
or
(inputVariable is null or inputVariable not in ('0', '1'))
and (status = 999 or status is null) and date >= [whatever]
Note - even in the absence of null handling, you can't write the where clause with a case expression; that's because in one branch you require "not equal", and you can't do it with a simple case expression.

Any vs Where clause in LINQ

I always thought LINQ to SQL equivalent for an exists query is to use Any(). But i recently wrote a query in LINQ , which basically is trying to find if duplicate records exists in single table.
Anycontext.Contacts.Any(c => ((c.FirstName == contact.FirstName && c.LastName == contact.LastName && c.AddressLine1 == contact.AddressLine1 && c.Zip == contact.Zip)||
(!String.IsNullOrEmpty(contact.Email) && c.Email == contact.Email)))
matching criteria is simple to find contacts with same FirstName, LastName and AddressLine1 or same Email. This query times out in 30 sec(default), there are just 500K rows in this table.
Wherecontext.Contacts.Where(c => ((c.FirstName == contact.FirstName && c.LastName == contact.LastName && c.AddressLine1 == contact.AddressLine1 && c.Zip == contact.Zip)||
(!String.IsNullOrEmpty(contact.Email) && c.Email == contact.Email))).Count()>0
I was forced to use Where clause and then do count greater than 0 to find if any duplicate exists in the set. What i can not understand is, why LINQ to SQL on simple Any clause timing out.
Any explanation will be really great here.
EDIT
SQL From from LINQ Pad
ANY
SELECT
(CASE
WHEN EXISTS(
SELECT NULL AS [EMPTY]
FROM [Accounts].[Contacts] AS [t0]
WHERE ([t0].[CompanyID] = #p0) AND ((([t0].[FirstName] = #p1) AND ([t0].[LastName] = #p2) AND ([t0].[AddressLine1] = #p3) AND ([t0].[Zip] = #p4)) OR (([t0].[FirstName] = #p5) AND ([t0].[LastName] = #p6) AND (EXISTS(
SELECT NULL AS [EMPTY]
FROM [Accounts].[PhoneNumbers] AS [t1]
WHERE ([t1].[ContactNumber] = #p7) AND ([t1].[ContactID] = [t0].[ContactID])
))))
) THEN 1
ELSE 0
END) AS [value]
Where
SELECT [t0].[ContactID]
,[t0].[CompanyID]
,[t0].[CompanyTitle]
,[t0].[FirstName]
,[t0].[LastName]
,[t0].[AddressLine1]
,[t0].[AddressLine2]
,[t0].[City]
,[t0].[State]
,[t0].[Zip]
,[t0].[Email]
,[t0].[Salutation]
,[t0].[IsActive]
FROM [Accounts].[Contacts] AS [t0]
WHERE ([t0].[CompanyID] = #p0)
AND (
(
([t0].[FirstName] = #p1)
AND ([t0].[LastName] = #p2)
AND ([t0].[AddressLine1] = #p3)
AND ([t0].[Zip] = #p4)
)
OR (
([t0].[FirstName] = #p5)
AND ([t0].[LastName] = #p6)
AND (
EXISTS (
SELECT NULL AS [EMPTY]
FROM [Accounts].[PhoneNumbers] AS [t1]
WHERE ([t1].[ContactNumber] = #p7)
AND ([t1].[ContactID] = [t0].[ContactID])
)
)
)
)
Not completely sure if this is what you want, but you could compare, I'm guessing you wont run the test often, as it would be better to test for existence before you input the data to the DB.
If you want to find the duplicates then
var queryA = from a in db.someTable
select a.value;
foreach(var row in queryA){
Console.Write(queryA.Where(b => b == row).Count() > 1 ? row: "");
}
If you just want to test if it exist then.
var queryA = from a in db.someTable
select a.value;
var queryB = queryA;
queryB.Distinct();
Console.Write(queryB.Count() != queryA.Count() ? "Yes" : "No");

Trigger on one table field works for all table fields

I have a trigger which is for a few fields in a table. But for some reason, if another field is changed (which is not defined in trigger) then it still fires.
CREATE OR REPLACE TRIGGER INTEGRATION_EMPLOYMENT
AFTER UPDATE OF start_day_of_employment, end_of_employment ON hr_employment_data
FOR EACH ROW
DECLARE
BEGIN
IF UPDATING THEN
MERGE INTO ad_integration intg USING dual ON (intg.user_id = :NEW.user_id AND intg.integrated = 'NO')
WHEN MATCHED THEN
UPDATE SET
intg.start_day_of_employment = decode(:NEW.start_day_of_employment, NULL, ' ', :NEW.start_day_of_employment),
intg.end_of_employment = decode(:NEW.end_of_employment, NULL, ' ', :NEW.end_of_employment),
intg.manager_status = :NEW.manager_status,
intg.pid = (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id),
intg.network_access_start_date = (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id)
WHEN NOT MATCHED THEN
INSERT (intg.user_id, intg.start_day_of_employment, intg.end_of_employment, intg.manager_status, intg.pid, intg.network_access_start_date
VALUES (:NEW.user_id, :NEW.start_day_of_employment, :NEW.end_of_employment, :NEW.manager_status, (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id), (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id));
END IF;
END HR_ADINTEGRATION_EMPLOYMENT;
Is it because of using DUAL or something am I missing?
Cheers! :-)
If you want to leave the structure as is and only process the trigger when the specifc fields change, then just do a quick compare (new code lines 7 and 8):
CREATE OR REPLACE TRIGGER INTEGRATION_EMPLOYMENT
AFTER UPDATE OF start_day_of_employment, end_of_employment ON hr_employment_data
FOR EACH ROW
DECLARE
BEGIN
IF UPDATING
AND (:NEW.start_day_of_employment <> :OLD.start_day_of_employment
OR :NEW.end_of_employment <> :OLD.end_of_employment) THEN
MERGE INTO ad_integration intg USING dual ON (intg.user_id = :NEW.user_id AND intg.integrated = 'NO')
WHEN MATCHED THEN
UPDATE SET
intg.start_day_of_employment = decode(:NEW.start_day_of_employment, NULL, ' ', :NEW.start_day_of_employment),
intg.end_of_employment = decode(:NEW.end_of_employment, NULL, ' ', :NEW.end_of_employment),
intg.manager_status = :NEW.manager_status,
intg.pid = (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id),
intg.network_access_start_date = (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id)
WHEN NOT MATCHED THEN
INSERT (intg.user_id, intg.start_day_of_employment, intg.end_of_employment, intg.manager_status, intg.pid, intg.network_access_start_date
VALUES (:NEW.user_id, :NEW.start_day_of_employment, :NEW.end_of_employment, :NEW.manager_status, (SELECT pid FROM arc.user_info WHERE user_id = :NEW.user_id), (SELECT network_access_start_date FROM hr_extension_data WHERE user_id = :NEW.user_id));
END IF;
END HR_ADINTEGRATION_EMPLOYMENT;

Using select in select in oracle report query

I am creating a new report where I have only one cursor in the report and the report has no paper layout (it goes directly to a CSV format).
I have a query where I need to make a sub query something like
SELECT
grou.GROUP_ID GROUP_ID
,grou.group_name group_name
....
(((SELECT SUM(nett_instalment_invoice_amount)
FROM instalments
WHERE member_product_id = member_product_id)) subscription)
FROM
....
and so on....
While compiling report I encounter an error saying
Encountered Symbol SELECT while expecting one of the following symbols:
( + -
can this be helped without adding a group by clause at the end?
As I tried an alternative approach by putting in a group by clause and directly using sum function instead of select (sum()).
Please urgent help needed.
Thanks.
there is a simple workaround for this by creating a function let's call it get_installment_inv_sum with one parameter member_product_id like this:
create or replace function get_installment_inv_sum (p_member_product_id number) return number
as
v_sum number
begin
SELECT SUM(nett_instalment_invoice_amount)
into v_sum
FROM instalments
WHERE member_product_id = p_member_product_id;
return v_sum;
end;
then you can call your select like:
SELECT
grou.GROUP_ID GROUP_ID
,grou.group_name group_name
....
,
get_installment_inv_sum(member_product_id) subscription
FROM ...
This is certainly allowed:
select d.dname, (sum(e.sal) from emp e where e.deptno = d.deptno) as dept_sal
from dept d;
And so is this:
select d.dname, sum(e.sal)
from dept d
left outer join emp e on e.deptno = d.deptno
group by d.dname;
So what did you do exactly?
SELECT /*+ ORDERED PUSH_SUBQ*/
11
,'SQ'
,grou.GROUP_ID GROUP_ID
,grou.group_name group_name
,intm.intermediary_id intermediary_id --R3352 AUS Regulatory added new field
,intm.intermediary_name intermediary_name
,regi.registration_id registration_id
,mere.member_id member_id
,memb.title_code title_code
,memb.given_name||' '||memb.family_name member_name
--,mech.birth_date birth_date
,mere.company_employee_ref company_employee_ref
,memb.orig_risk_start_date orig_risk_start_date
,mere.original_bi_joining_date orig_joining_date
,mepr.member_product_id member_product_id
,mepr.member_product_risk_start_date mp_risk_start_date
,mepr.product_id product_id
,INITCAP(prod.product_name) product_name
,cont.currency_code
,mere.customer_status_code
/* ,((SELECT SUM(inst.nett_instalment_invoice_amount)
FROM instalments inst
WHERE inst.member_product_id = mepr.member_product_id)) subscription */
,SUM(inst.nett_instalment_invoice_amount) subscription
FROM registrations regi
,member_registrations mere
,member_products mepr
,contracts cont
,products prod
,members memb
,groups grou
,intermediaries intm
,insurers insu
,instalments inst
WHERE insu.insurer_id = i_insurerid
AND NVL(i_reportdate ,Sysdate) >= cont.contract_risk_start_date
AND NVL(i_reportdate ,Sysdate) < cont.renewal_date
--AND regi.GROUP_ID IN (77648,77658) --Arv
AND prod.insurer_id = insu.insurer_id(+)
AND mere.member_id = memb.member_id
AND mere.member_id = mepr.member_id
AND mepr.contract_pk = cont.contract_pk
AND mepr.product_id = prod.product_id(+)
AND mepr.intermediary_id = intm.intermediary_id(+)
AND mere.registration_id = regi.registration_id
AND mere.registration_id = mepr.registration_id
AND regi.GROUP_ID = grou.group_id
AND inst.member_product_id = mepr.member_product_id
AND grou.group_level_code IN ('G','R')
AND mere.customer_status_code IN ('A','L')
AND family_name_uppercase <> UPPER('zz** Please Ignore This Member **zz')
AND given_name_uppercase <> UPPER('zz** Please Ignore **zz') --l_given_name_uppercase
AND NOT EXISTS
( SELECT 'X'
FROM customer_lapses
WHERE GROUP_ID = regi.GROUP_ID
AND suspend_lapse_ind = 'L'
AND reinstatement_ind = 'N'
AND lapse_effective_date <= NVL(i_reportdate ,Sysdate)
UNION
SELECT 'X'
FROM customer_lapses
WHERE registration_id = regi.registration_id
AND suspend_lapse_ind = 'L'
AND reinstatement_ind = 'N'
AND lapse_effective_date <= NVL(i_reportdate ,Sysdate)
)
AND NOT EXISTS
( SELECT 'X'
FROM customer_lapses
WHERE mem_reg_member_id = mere.member_id
AND mem_reg_registration_id = mere.registration_id
AND suspend_lapse_ind = 'L'
AND reinstatement_ind = 'N'
AND lapse_effective_date <= NVL(i_reportdate ,Sysdate)
)
AND NOT EXISTS
( SELECT 'X'
FROM customer_lapses
WHERE member_product_id = mepr.member_product_id
AND suspend_lapse_ind = 'L'
AND reinstatement_ind = 'N'
AND lapse_effective_date <= NVL(i_reportdate ,Sysdate)
UNION
SELECT 'X'
FROM customer_lapses
WHERE cust_prod_contract_pk = mepr.contract_pk
AND cust_prod_product_id = mepr.product_id
AND suspend_lapse_ind = 'L'
AND reinstatement_ind = 'N'
AND lapse_effective_date <= NVL(i_reportdate ,Sysdate)
)
Group BY 11
,'SQ'
,grou.GROUP_ID -- GROUP_ID
,grou.group_name -- group_name
,intm.intermediary_id -- intermediary_id --R3352 AUS Regulatory added new field
,intm.intermediary_name -- intermediary_name
,regi.registration_id -- registration_id
,mere.member_id -- member_id
,memb.title_code -- title_code
,memb.given_name||' '||memb.family_name -- member_name
--,mech.birth_date birth_date
,mere.company_employee_ref -- company_employee_ref
,memb.orig_risk_start_date -- orig_risk_start_date
,mere.original_bi_joining_date -- orig_joining_date
,mepr.member_product_id -- member_product_id
,mepr.member_product_risk_start_date -- mp_risk_start_date
,mepr.product_id -- product_id
,INITCAP(prod.product_name) -- product_name
,cont.currency_code
,mere.customer_status_code
Which version of Oracle Reports ?
The scalar subqueries syntax came in around Oracle 8/8i, but the development of Oracle reports stopped sometime around the stone-age. A lot of the enhanced SQL syntax of the last 10+ years hasn't made it in.
If you can create the bulk of the query as a view in the database, and just select from the view in the report, then you have more flexibility

Resources