How to increase performance of merge statement in SQL server - sql

I have to execute merge statement on SQL server DB with below requirement.
MERGE INTO dbo.cross_charge D
USING
(
SELECT
PROJECT_CODE
, CROSS_CHARGE_OU
FROM
dbo.cross_charge
WHERE
PROJECT_CODE = #PROJECT_CODE1
AND CROSS_CHARGE_OU = #CROSS_CHARGE_OU1
) S
ON (
D.PROJECT_CODE = S.PROJECT_CODE
AND D.CROSS_CHARGE_OU = S.CROSS_CHARGE_OU
)
WHEN MATCHED THEN UPDATE SET
D.PROJECT_CODE = #PROJECT_CODE3
, D.CROSS_CHARGE_OU = #CROSS_CHARGE_OU3
, D.CROSS_CHARGE_START = #CROSS_CHARGE_START1
, D.CROSS_CHARGE_END = #CROSS_CHARGE_END1
, D.IS_Enable = #IS_Enable1
, D.UpdatedDate = #UpdatedDate1
WHEN NOT MATCHED THEN INSERT
(
PROJECT_CODE
, CROSS_CHARGE_OU
, CROSS_CHARGE_START
, CROSS_CHARGE_END
, IS_Enable
, UpdatedDate
)
VALUES
(
#PROJECT_CODE2, #CROSS_CHARGE_OU2, #CROSS_CHARGE_START, #CROSS_CHARGE_END, #IS_Enable, #UpdatedDate
)
I have to pass Project_code and cross_charge_ou as input parameter and based on select result it will either insert or update the record.
When I am executing this query for 100 records then It is taking 35 seconds which is too much as I have to execute this statement for 50K+ records.
Do we have any options to improve the performance of this query as I am not much aware of SQL?
Thank you.

Related

DB2 - SQL UPDATE statement using JOINS and SELECT statement

Morning,
I'm running the following SELECT statement on a DB2 server (IBM Power System) and it returns the latest record from tableB based on a Timestamp (all good).
SELECT * FROM library1/tableA
JOIN library1/tableB on tableB.PRDCOD = tableA.NPROD
WHERE tableB.PRDCOD = '5520' and tableA.SPRTXT01 <> '0/9'
ORDER BY tableB.timstp DESC FETCH NEXT 1 ROWS ONLY
I now need to change this statement to update tableA and set field SPRTXT01 = '0/9', but only if tableB.SRVRSP= 'SUCCESSFUL' i.e. the latest record from tableB has a response of 'SUCCESSFUL'.
But I don't know how to format this statement correctly. Can anyone assist please?
I've tried the below, but this updated ALL rows in the table
UPDATE library1/tableA
SET tableA.SPRTXT01 = '0/9'
Where exists (
Select '1'
FROM library1/tableA
JOIN library1/tableB on
tableB.PRDCOD = tableA.NPROD
WHERE tableB.PRDCOD = '5520' and tableB.SRVRSP = 'SUCCESSFUL'
and tableA.SPRTXT01 <> '0/1'
ORDER BY tableB.timstp DESC FETCH NEXT 1 ROWS ONLY)
and I don't think it's applying the selection correctly i.e. rather than selecting the latest record from table B and then applying the RVSRP = 'SUCCESSFUL' check, it is only selecting the latest record for table B where SRVSRP = 'SUCCESSFUL'.
Thanks
Try this:
CREATE TABLE tableA (NPROD VARCHAR (10), SPRTXT01 VARCHAR (3));
CREATE TABLE tableB (PRDCOD VARCHAR (10), SRVRSP VARCHAR (20), timstp TIMESTAMP);
INSERT INTO tableA (NPROD, SPRTXT01)
VALUES ('5520', ''), ('XXXX', '');
INSERT INTO tableB (PRDCOD, SRVRSP, timstp)
VALUES
('5520', 'SUCCESSFUL', CURRENT TIMESTAMP)
, ('5520', 'UNSUCCESSFUL', CURRENT TIMESTAMP + 1 SECOND)
-- Comment out the next row to make it NOT update the SPRTXT01 column
, ('5520', 'SUCCESSFUL', CURRENT TIMESTAMP + 2 SECOND)
;
UPDATE tableA
SET tableA.SPRTXT01 = '0/9'
Where tableA.NPROD = '5520' AND tableA.SPRTXT01 <> '0/9'
AND exists
(
SELECT 1
FROM tableB
JOIN (SELECT PRDCOD, MAX (timstp) AS timstp FROM tableB GROUP BY PRDCOD) G
ON (G.PRDCOD, G.timstp) = (tableB.PRDCOD, tableB.timstp)
WHERE tableB.PRDCOD = tableA.NPROD
AND tableB.SRVRSP = 'SUCCESSFUL'
);
SELECT * FROM tableA;
NPROD
SPRTXT01
5520
0/9
XXXX
fiddle

Looking for the best way to return pass in a parameter to allow me to return a specific customer or all customers in SQL

I have the below query that could defenitely be optimized but I'm looking for the best way to add a parameter that allows me to return the same results and pass in a Parameter that would say if pass it in as "All" it would return all WO.BillTo records but if I passed in a value other than "All" it would compare that value to the WO.BillTo to only return records for that specific BillTo Customer.
Any help or suggestions would be greatly appreciated.
SELECT WO.WONo ,
WO.BillTo ,
WO.ShipTo ,
WO.ShipName ,
WO.ClosedDate ,
WOParts.PartNo ,
WOParts.Description ,
WOParts.ShipQty ,
WOParts.SellRate ,
Customer.Name
FROM WO,WOParts,Customer
WHERE (((
((WO.ClosedDate >= #startdate ) AND (WO.ClosedDate < #closedate ) )
AND (WO.Disposition = 2 ) )
AND (WO.WONo = WOParts.WONo ) )
AND (WO.BillTo = Customer.Number ) )
AND WOParts.TransferWONoTo =''
and Woparts.shipqty <> 0
order by wo.ShipTo
This is known as a "catch all" query. I would suggest using NULL rather than 'all', but the syntax would be the same. The OPTION (RECOMPILE) is there to stop poor query plan caching. Also I've "updated" you to 1992's ANSI-92 explicit JOIN syntax, as it has been around for around 30 years now:
SELECT W.WONo ,
W.BillTo ,
W.ShipTo ,
W.ShipName ,
W.ClosedDate ,
WP.PartNo ,
WP.Description ,
WP.ShipQty ,
WP.SellRate ,
C.Name
FROM dbo.WO W --Let's update to 1992!
JOIN dbo.WOParts WP ON W.WONo = WP.WONo
JOIN dbo.Customer C ON W.BillTo = C.Number
WHERE W.ClosedDate >= #startdate AND W.ClosedDate < #closedate
AND W.Disposition = 2
AND WP.TransferWONoTo =''
AND WP.shipqty <> 0
AND (WO.BillTo = #YourParameter OR #YourParameter IS NULL)
ORDER BY W.ShipTo
OPTION (RECOMPILE);

Oracle SQL Insert whit Case Select

I'm new in this site and I have another question. In this case, it is from Oracle SQL, Insert operation with a CASE.
My SQL insert's code is:
INSERT WHEN (SELECT TB0083_DS_TIPODISPOSITIVO FROM TB0083_TIPODISPOSITIVO WHERE TB0083_ID_TIPODISPOSITIVO = (SELECT FOR_DISPOSITIVO FROM TFORPD01 WHERE FOR_CODIGO = &FORNECEDOR))='TIV' THEN
INTO TTRAPD01 (TRA_CODIGO,TRA_CODBARRA,TRA_CODLOC,TRA_CODCON,TRA_DATLOC,TRA_CODCAIXA,TRA_STATCOND,TRA_DT_CRIACAO,TRA_NM_USUARIOCRIACAO,TRA_DT_ALTERACAO,TRA_NM_USUARIOALTERACAO,TRA_CD_CONTA,TRA_CODCTR,TRA_TRANSACAO_ONLINE,TRA_TIV_HEXA,TRA_TIV_BINARIO,TRA_CD_DISPOSITIVO,TRA_DATSINC,TRA_ID_TPSEGREG,TRA_FORNECEDOR,TRA_STATUS)
VALUES (&NUMEROIDENTIFICADOR,&CODIGOBARRAIDENTIFICADOR,&CODIGOPONTOVENDALARM,259,SYSDATE,&CODIGOCAIXA,0,SYSDATE,&USUARIOLOGUEADO,SYSDATE,&USUARIOLOGUEADO,422,1,0,&TIVHEXA,&TIVBINARIO,423,SYSDATE,3,&FORNECEDOR,1)
ELSE
INTO TTRAPD01 (TRA_CODIGO,TRA_CODBARRA,TRA_CODLOC,TRA_CODCON,TRA_DATLOC,TRA_CODCAIXA,TRA_STATCOND,TRA_DT_CRIACAO,TRA_NM_USUARIOCRIACAO,TRA_DT_ALTERACAO,TRA_NM_USUARIOALTERACAO,TRA_CD_CONTA,TRA_CODCTR,TRA_TRANSACAO_ONLINE,TRA_TIV_HEXA,TRA_TIV_BINARIO,TRA_CD_DISPOSITIVO,TRA_DATSINC,TRA_ID_TPSEGREG,TRA_FORNECEDOR,TRA_STATUS)
VALUES (&NUMEROIDENTIFICADOR,&CODIGOBARRAIDENTIFICADOR,&CODIGOPONTOVENDALARM,259,SYSDATE,&CODIGOCAIXA,0,SYSDATE,&USUARIOLOGUEADO,SYSDATE,&USUARIOLOGUEADO,422,1,0,&TIVHEXA,&TIVBINARIO,423,SYSDATE,2,&FORNECEDOR,1);
This script doesn't found.
I need to fix it, because I need to change the value of field TRA_ID_TPSEGREG depends on the value of:
SELECT TB0083_DS_TIPODISPOSITIVO FROM TB0083_TIPODISPOSITIVO WHERE TB0083_ID_TIPODISPOSITIVO = (SELECT FOR_DISPOSITIVO FROM TFORPD01 WHERE FOR_CODIGO = &FORNECEDOR)
If value is 'TIV' then it inserts 3 in that position, else it inserts 2 in those field.
Thanks!!
There's PL/SQL INSERT WHEN command:
Try this:
INSERT FIRST
WHEN TB0083_DS_TIPODISPOSITIVO = 'TIV' THEN
INTO TTRAPD01
(
<COLUMN_NAME1>,<COLUMN_NAME2>......
)
VALUES
(
<COLUMN_VALUE1>,<COLUMN_VALUE2>.....
)
ELSE
INTO TTRAPD01
(
<COLUMN_NAME1>,<COLUMN_NAME2>......
)
VALUES
(
<COLUMN_VALUE1>,<COLUMN_VALUE2>.....
)
SELECT TB0083_DS_TIPODISPOSITIVO
FROM TB0083_TIPODISPOSITIVO
WHERE TB0083_ID_TIPODISPOSITIVO =
(SELECT FOR_DISPOSITIVO FROM TFORPD01 WHERE FOR_CODIGO = &FORNECEDOR
);
For eg:
CREATE TABLE TEST ( ID NUMBER);
INSERT FIRST
WHEN dummy = 'Y' THEN
INTO TEST
VALUES(222)
ELSE
INTO TEST
VALUES(555)
select dummy from dual;
The above query will insert 1 ROW on the very first condition satisfy. See more: >>here<<

How to find out non unique records?

SELECT TRD.PKG_ID||'_'||TRD_CONT_NBR||'_'||LEG.TRD_LEG_NBR||'_'|| TRD.TRD_ID||'_'||CF.CURR_CODE||'_'||cf.cflw_date||'_'||CF.CFLW_TYPE_CODE
||'_'||CF.CFLW_STATUS_CODE as Surrogate_key
, CF.EFF_DATE, TRD.PKG_ID, TRD_CONT_NBR, TRD.SRCE_TRD_ID
, LEG.TRD_LEG_NBR, TRD.TRD_ID, LEG.TRD_LEG_ID
, CF.CURR_CODE, cf.cflw_date, CF.TRD_CURR_CASH_FLOW_AMT
, CF.INT_RATE, cf.INT_RATE, CF.CFLW_TYPE_CODE, CF.CFLW_TYPE_GRP_CODE
, CF.CFLW_STATUS_CODE
from edw.extv_t_dim_trd TRD
, edw.extv_t_trade_leg LEG
, edw.extv_fact_cash_flow CF
where TRD.SRCE_TRD_ID = CF.SRCE_TRD_ID
and TRD.TRD_ID = CF.TRD_ID
and CF.SRCE_TRD_ID = LEG.SRCE_TRD_ID
and CF.TRD_LEG_ID = LEG.TRD_LEG_ID
and TRD.SRCE_SYS_CODE = 'WSS'
and cf.SRCE_SYS_CODE = 'WSS'
and leg.SRCE_SYS_CODE = 'WSS'
AND TRD.TRD_STATUS_CODE <> 'CANCELED'
AND LEG.INSTM_TYPE_CODE NOT IN ('FX', 'FX-OPTION')
AND TRD.TRD_ACTV_TO_DATE >= to_date('04/01/2013','mm/dd/yyyy')
and TRd.TECH_TRD_FLAG = 'N'
and cf.cflw_status_code = 'FINAL'
and TRD.ACTV_FLAG = 'Y'
and LEG.ACTV_FLAG = 'Y'
and cf.actv_flag ='Y'
With the above query, if add distinct in Surrogate_key I was able to find out the unique values but my problem is the overall record for the query is 3 million.. With distinct 2.5 million but I Would like to find non stop unique value of. 5 million. So how can I achieve that?
And one more in some cases we were not having primary key in the table so I use to form Surrogate_key . Even that was also contains some duplicate values. Future what kind of method if I need to use to avoid such problem.
Thanks,
Srini
I do not undestand all your problem, but assuming that you want to search duplicates of surrogate_key then maybe this script will be useful:
CREATE TABLE TEST(
Surrogate_key VARCHAR2(100));
INSERT INTO TEST VALUES('AAAA');
INSERT INTO TEST VALUES('ACAA');
INSERT INTO TEST VALUES('AAAA');
INSERT INTO TEST VALUES('AAAB');
INSERT INTO TEST VALUES('AAAA');
INSERT INTO TEST VALUES('ACAA');
/*HERE THE QUERY*/
SELECT T.Surrogate_key, COUNT(1) AS MATCHES
FROM TEST T
GROUP BY T.Surrogate_key
HAVING COUNT(1) > 1
You can try this here.
(EDITED 2013-07-15)
Assuming that your query works, then try this (with this you can find the repeated rows):
SELECT T.Surrogate_key, COUNT(1) AS MATCHES
FROM (
SELECT TRD.PKG_ID||'_'||TRD_CONT_NBR||'_'||LEG.TRD_LEG_NBR||'_'|| TRD.TRD_ID||'_'||CF.CURR_CODE||'_'||cf.cflw_date||'_'||CF.CFLW_TYPE_CODE
||'_'||CF.CFLW_STATUS_CODE as Surrogate_key
from edw.extv_t_dim_trd TRD
, edw.extv_t_trade_leg LEG
, edw.extv_fact_cash_flow CF
where TRD.SRCE_TRD_ID = CF.SRCE_TRD_ID
and TRD.TRD_ID = CF.TRD_ID
and CF.SRCE_TRD_ID = LEG.SRCE_TRD_ID
and CF.TRD_LEG_ID = LEG.TRD_LEG_ID
and TRD.SRCE_SYS_CODE = 'WSS'
and cf.SRCE_SYS_CODE = 'WSS'
and leg.SRCE_SYS_CODE = 'WSS'
AND TRD.TRD_STATUS_CODE <> 'CANCELED'
AND LEG.INSTM_TYPE_CODE NOT IN ('FX', 'FX-OPTION')
AND TRD.TRD_ACTV_TO_DATE >= to_date('04/01/2013','mm/dd/yyyy')
and TRd.TECH_TRD_FLAG = 'N'
and cf.cflw_status_code = 'FINAL'
and TRD.ACTV_FLAG = 'Y'
and LEG.ACTV_FLAG = 'Y'
and cf.actv_flag ='Y'
) T
GROUP BY T.Surrogate_key
HAVING COUNT(1) > 1

Odd WHERE NOT EXISTS performance on DB2

I am experiencing very odd performance on DB2 version 9.1 when running the query below:
select a.CYCL_NUM
, a.AC_NUM
, a.AUTHS_DTE
, a.PL_ID
, a.APRVD_RSPN_CDE
, a.AUTHS_AMT
, a.AUTHS_STS_CDE
, a.TRAN_CTGR_CDE
, a.MRCHN_CTGR_CDE
, d.out_pu_au_amt
from nwhd12.chldr_auths a, nwhd12.w_chldr_ac d
where cycl_num = 200911
and a.ac_num = d.ac_num
and APRVD_RSPN_CDE = 'APV'
and not exists (
select 1 from auths_rev_hist b
where a.cycl_num = b.cycl_num
and a.auths_dte = b.auths_dte
and a.TRAN_CTGR_CDE = b.TRAN_CTGR_CDE
and a.PL_ID = b.pl_id
and a.APRVD_RSPN_CDE = b.APRVD_RSPN_CDE
and a.AUTHS_AMT = b.auths_amt
and a.TRAN_CTGR_CDE = b.TRAN_CTGR_CDE
and a.MRCHN_CTGR_CDE = MRCHN_CTGR_CDE
)
;
What is supposed to happen is that the query accesses partion 97 of nwhd12.chldr_auths, since that is the partition corresponding to cycle 200911. Instead, after accessing partition 97, it starts accessing every other partition in nwhd12.chldr_auths. Now, I was told that this is because of the "WHERE NOT EXISTS", but there is still the restriction on cycles in this statement (a.cycl_num = b.cycl_num), so why is it scanning all the partitions?
If I hard code the cycle in the where not exists, then the query performs as expected.
Thanks,
Dave
if the planner is this easily confused, you need to try a few different formulations. this untested (I don't even have DB2, but CTEs originated there):
WITH hist AS (
cycl_num
, ac_num
, auths_dte
, pl_id
, aprvd_rspn_cde
, auths_amt
, auths_sts_cde
, tran_ctgr_cde
, mrchn_ctgr_cde
FROM auths_rev_hist b
)
, auths AS (
SELECT
cycl_num
, ac_num
, auths_dte
, pl_id
, aprvd_rspn_cde
, auths_amt
, auths_sts_cde
, tran_ctgr_cde
, mrchn_ctgr_cde
FROM nwhd12.chldr_auths
WHERE cycl_num = 200911
AND aprvd_rspn_cde = 'APV'
EXCEPT
SELECT ... FROM hist
)
SELECT a.*, d.out_pu_au_amt
FROM auths a, nwhd12.w_chldr_ac d
WHERE a.ac_num = d.ac_num