how to optimize my oracle query? - database

I have a query very slow and I want to optimize it. I've created index on fields for the joins. My query is this:
SELECT DISTINCT
--a.row_id FK_SERVIZIO,
--CLI_UNICO.FK_CLIENTE FK_CLIENTE,
CLI.CDC_FISCALE CDC_FISCALE,
--com.descrizione
--CASE WHEN conc.COMUNE IS NOT NULL THEN 1 ELSE 0 END FL_OFFERTABILITA_GAS
CASE WHEN exists (select 1 from STG.T_STG_NBA_DT_S_ASSET_G a where a.owner_accnt_id=CLI.IDC_CLIENTE_CRM_KEY and status_cd in ('ATTIVATO'))
THEN 'SI' ELSE 'NO' END FLC_COMUNE_TERR
FROM STG.T_STG_NBA_DT_S_ASSET_G A,
STG.T_STG_PSP_DT_LISTA_COMUNI_TERR terr,
STG.T_STG_NBA_DT_R2DG_COMUNI_G com,
STG.T_STG_NBA_DT_S_ADDR_PER_G ind_for,
--STG.V_DML_NBA_SITO q,
ODS.T_ODS_CRM_DT_CLIENTI_CRM CLI,--ODS.V_ODS_NBA_DT_ASS_CLI_CLIUNICO CLI_UNICO,
STG.T_STG_NBA_DT_S_ORG_EXT_G cforn
--STG.T_STG_NBA_DT_R2DG_CONCESS_G conc,
WHERE
--CLI.IDC_CLIENTE_CRM_KEY=A.OWNER_ACCNT_ID
terr.LDS_DESCRIZIONE_COMUNE=com.DESCRIZIONE
AND com.CODICE_ISTAT=ind_for.x_cod_istat
AND ind_for.row_id = cforn.PR_ADDR_ID
and cforn.row_id=A.serv_acct_id
i put index on this fields:
terr.LDS_DESCRIZIONE_COMUNE,com.DESCRIZIONE,com.CODICE_ISTAT,ind_for.x_cod_istat,ind_for.row_id,cforn.PR_ADDR_ID,cforn.row_id,A.serv_acct_id,a.owner_accnt_id,CLI.IDC_CLIENTE_CRM_KEY, a.status_cd.
any tips for me pls?
i can use PARALLEL? how?
THANKS

A sub select in the Select-Clause can hamper your performance badly. Just try to get rid of it.
You could do something like that
SELECT DISTINCT
--a.row_id FK_SERVIZIO,
--CLI_UNICO.FK_CLIENTE FK_CLIENTE,
CLI.CDC_FISCALE CDC_FISCALE,
--com.descrizione
--CASE WHEN conc.COMUNE IS NOT NULL THEN 1 ELSE 0 END FL_OFFERTABILITA_GAS
decode(test.cnt, 0 'NO', 'SI') FLC_COMUNE_TERR
FROM STG.T_STG_NBA_DT_S_ASSET_G A,
STG.T_STG_PSP_DT_LISTA_COMUNI_TERR terr,
STG.T_STG_NBA_DT_R2DG_COMUNI_G com,
STG.T_STG_NBA_DT_S_ADDR_PER_G ind_for,
--STG.V_DML_NBA_SITO q,
ODS.T_ODS_CRM_DT_CLIENTI_CRM CLI,--ODS.V_ODS_NBA_DT_ASS_CLI_CLIUNICO CLI_UNICO,
STG.T_STG_NBA_DT_S_ORG_EXT_G cforn,
--STG.T_STG_NBA_DT_R2DG_CONCESS_G conc,
(select count(*) cnt from STG.T_STG_NBA_DT_S_ASSET_G a where a.owner_accnt_id=CLI.IDC_CLIENTE_CRM_KEY and status_cd in ('ATTIVATO')) test
WHERE
--CLI.IDC_CLIENTE_CRM_KEY=A.OWNER_ACCNT_ID
terr.LDS_DESCRIZIONE_COMUNE=com.DESCRIZIONE
AND com.CODICE_ISTAT=ind_for.x_cod_istat
AND ind_for.row_id = cforn.PR_ADDR_ID
and cforn.row_id=A.serv_acct_id

Related

Rank and date change case expression

I am trying to show the second part below. If a person goes from high to low it is good but if they go from low to high it is bad. Any ideas on how I'd accomplish this? I have the SQL to return the top part but not sure how to get the second part.
you propably looking for lag function
select membno, rancs, date_rank
, case
when lag(rancs, 1, rancs) over (partition by membno order by date_rank) > rancs then 'GOOD'
when lag(rancs, 1, rancs) over (partition by membno order by date_rank) < rancs then 'BAD'
else 'i do''n know'
end second_part_for_current_row
from something
for global resoult use self join:
select curr.membno, prev.rancs, curr.rancs
, case
when prev.rancs > curr.rancs then 'GOOD'
when prev.rancs < curr.rancs then 'BAD'
else 'i do''n know'
end second_part
from something curr
left join something prev on curr.membno = prev.membno and curr.date_rank = prev.date_rank + 1
where not exists (select 1 from something pres where pres.membno = curr.membno and curr.date_rank + 1 = pres.date_rank)

Fix 'Incorrect syntax near the keyword 'WHEN'' error in SQL Server?

I'm trying to implement this two when condition in the case expression but it is just not happening. Please help me fix this?
SELECT
BR, CID, TRNDATE,
CASE
WHEN TRNTYPE = '108' THEN -1 ELSE 1 * TrnAmt/100
WHEN TRNTYPE = '114' THEN (TrnIntAmt - TrnTaxAmt)/100
END as TransactionAmount
FROM
T_TRNHIST
Query Must be like that
SELECT BR, CID, TRNDATE,
CASE
WHEN TRNTYPE = '108' THEN -1
WHEN TRNTYPE = '114' THEN (TrnIntAmt - TrnTaxAmt)/100
ELSE 1 * TrnAmt/100
END as TransactionAmount
FROM T_TRNHIST
Else condition would come at last once all when done
just a little change, move the ELSE to before the END
SELECT BR, CID, TRNDATE,
CASE
WHEN TRNTYPE = '108' THEN -1
WHEN TRNTYPE = '114' THEN (TrnIntAmt - TrnTaxAmt)/100
else 1 * TrnAmt/100
END as TransactionAmount
FROM T_TRNHIST

sum(case When.. AND) with multiple conditions not working

I am trying to run this sum query to produce two columns of Turnover one for TY and another for LY. However, I want any transactions flagged as Cancelled to appear as negatives:
select [Location],BR.BranchName,
sum(case when (FX.TransactionDateKey between '20171101' and '20181031')
and ([Action] = 'Cancelled')
then FX.CustomerValue*-1 else [CustomerValue] end) as [CustmVal TY],
sum(case when (FX.TransactionDateKey between '20161101' and '20171031')
and ([Action] = 'Cancelled')
then FX.CustomerValue*-1 else FX.CustomerValue*1 end) AS [CustmVal LY]
from [dbo].[FRX_Transactions] FX
inner join DWX_Branch BR on BR.BranchID=FX.[Location]
where FX.TransactionDateKey between '20161101' and '20181031' and BR.BusinessDivision = 'Retail'
and FX.[Action] in ('Trade','cancelled') and FX.Reason in ('Public','BBG','Overridesupplyrate') and FX.Operation in ('Add','Del')
group by FX.[Location],BR.BranchName, BR.BranchOpenDate,BR.BranchCloseDate,BR.ActiveStatus
order by BR.BranchName
However, when I run it I get similar data in both columns - it seems to ignore the date conditions.
Please, what am I doing wrong? Is this case-when-statement with TWO conditions written wrong?
Any help would be HUGELY appreciated. Massive thanks!
I think what you actually want for your CASE expression is:
CASE WHEN FX.TransactionDateKey BETWEEN '20171101' AND '20181031' THEN [CustomerValue] *
CASE WHEN [Action] = 'Cancelled' THEN -1 ELSE 1 END
END

What is optimal number of tables we can use with JOINs?

I have a query which fetches records from 7 tables. All these tables are JOINed to get the details, few tables used multiple times with different ON clause. So there are 10 JOINs in the query. How can we optimize the query for getting better performance? We already have indexes on JOIN columns. Anything we can do to reduce the number of JOINs? Am using MS SQL 2012 with compatibility level 2008.
Query:
SELECT TOP 100
MT.ProjectId,
matRef,
matDescription,
matKeyDescription,
matOpenDate,
matUFN,
matBranchRef,
matClosedDate,
ERN1.feeRef,
WorkTypeCode,
DPT.deptNo AS matDeptRef,
PreviousRef,
MT.ApplicationID,
MatterCompleted,
CASE WHEN MLC.PFCivil_MatterCount = 0 THEN 0 ELSE 1 END AS IsCPF,
CASE WHEN MLC.PF_MatterCount = 0 THEN 0 ELSE 1 END AS IsPF,
CASE WHEN MLC.Family_MatterCount = 0 THEN 0 ELSE 1 END AS IsFM,
CASE WHEN MLC.WL_MatterCount = 0 THEN 0 ELSE 1 END AS IsWills,
CASE WHEN MLC.Convey_MatterCount = 0 THEN 0 ELSE 1 END AS IsConvey,
CASE WHEN MLC.Probate_MatterCount = 0 THEN 0 ELSE 1 END AS IsProbate,
CASE WHEN MLC.PI_MatterCount = 0 THEN 0 ELSE 1 END AS IsPi,
CASE WHEN MLC.PIPortal_MatterCount = 0 THEN 0 ELSE 1 END AS IsPiPortal,
CASE WHEN MLC.CM_MatterCount = 0 THEN 0 ELSE 1 END AS IsChest,
CASE WHEN MLC.Campaigns_MatterCount = 0 THEN 0 ELSE 1 END AS IsMarketing,
CASE WHEN MLC.PFFamilyFixedFee_MatterCount = 0 THEN 0 ELSE 1 END AS IsPFFamilyFixedFeeMatter,
ERN2.feeRef AS MatPartner,
MatPFCertificateNo,
CASE WHEN MT.matClosedDate = {d''1753-01-01''} THEN 0 ELSE 1 END AS IsArchived,
'''' Modules,
MT.ChargeDescID,
MT.MatterTypeID,
PrimaryClient.ClientName,
MB.LastAccDate,
MB.LastBillDate,
MB.LastClientDate,
MB.LastTimeDate
FROM dbo.Matter AS MT
JOIN dbo.Departments AS DPT ON DPT.deptID = MT.deptID
JOIN dbo.Earners AS ERN1 ON ERN1.MemberId = MT.MatFeeMemId
JOIN dbo.Earners AS ERN2 ON ERN2.MemberId = MT.matPartnerMemId
JOIN dbo.WorkTypes AS WT ON WT.WorkTypeID = MT.WorkTypeID
JOIN dbo.ivw_MatterLinkCount AS MLC ON MLC.ProjectId = MT.ProjectId
JOIN dbo.Banks AS ClientBank ON MT.matClientBank = ClientBank.bankID
JOIN dbo.Banks AS OfficeBank ON MT.matOfficeBank = OfficeBank.bankID
JOIN dbo.Banks AS DepositBank ON MT.matDepositBank = DepositBank.bankID
JOIN uvw_MatterPrimaryClient AS PrimaryClient ON PrimaryClient.ProjectId = MT.ProjectId
JOIN dbo.MatterBalance AS MB ON MT.ProjectId = MB.ProjectID
WHERE matDescription LIKE #Description
ORDER BY Isarchived, matRef
The trick here is that 'WHERE matDescription LIKE #Description' is not the real filter.
The real filter is 'TOP 100' together with 'ORDER BY Isarchived, matRef' because this filter will absolutely filter out anything but 100 rows.
So you need an index at Isarchived, matRef too. Table scan for matRef probably delays this one.
Also unless the Isarchived, matRef combination is unique by constraint, you better add the PK at the end like ORDER BY Isarchived, matRef, matid so there would be no extra problem picking the top 100.
Finally, if Isarchived is something like 0/1 and you have tons of records with 0 value it is useless at order by as there would always be 0. Set it as a filter Isarchived = 0 and remove it from order by - use matRef, matid and add a single index to matRef only.

case when but two columns instead of one column

I need some advice and suggestions if there is available some way of doing something like this:
SELECT Status=Case
WHEN clflf.product='active'
THEN 'Active' ELSE 'NotActive' END;
this basically creates active or notactive in one column.
Is there some way of doing a case when or some other technique so that I can have two columns, 'Active' and 'NotActive'?
You need separate case statements, like so.
Select StatusActive = Case when clflf.product='active' then 1 ELSE 0 end
,StatusNotActive = Case when clflf.product <>'active' then 1 ELSE 0 end
You can always do
SELECT active,
1 - active AS notactive
FROM clflf
CROSS APPLY (SELECT CASE
WHEN clflf.product = 'active' THEN 1
ELSE 0
END) CA(active)

Resources