Optimize query contains too many inner join and rows - sql

I have the following query
SELECT *
INTO ##TempStaffT
FROM Staff HF
WHERE HF.[businessline_id]='T'
AND HF.[offices_id] IN (SELECT * FROM ##TempParamOffice)
AND HF.[specialism_id]IN (SELECT * FROM ##TempParamSpecialism)
AND HF.[onetouch]IN (SELECT * FROM ##TempParamConsultant)
SET #sql4 = N'
INSERT INTO ##TempFees(' + #columns1 + ',CALF_AN ,BusinessName)
SELECT distinct ' + #columns2 + ',p.CALF_AN ,CB.[TempBusinessName] as BusinessName
FROM
dbo.WTEFAC EF
inner JOIN dbo.WTFAC F ON EF.EFAC_NUM = F.EFAC_NUM
inner JOIN dbo.WTFACINFO BS ON F.FAC_NUM = BS.FAC_NUM
inner JOIN dbo.WTLFAC LF ON F.FAC_NUM = LF.FAC_NUM
inner JOIN dbo.WTRUBVARIANTEFAC WRU ON LF.RINT_ID = WRU.RINT_ID
inner JOIN dbo.WTACUMFAC WTA ON WRU.RUV_ID = WTA.RUV_ID
inner JOIN ##CUM_CODEHT WTA1 ON WTA.CUM_ID = WTA1.CUM_ID
inner JOIN dbo.WTVTAT TAT ON BS.TIE_ID = TAT.TIE_ID AND BS.RFAN_ID = TAT.RFAN_ID AND BS.PER_ID = TAT.PER_ID AND BS.CNT_ID = TAT.CNT_ID
inner JOIN dbo.PYCONTRAT CC ON TAT.PER_ID = CC.PER_ID AND TAT.CNT_ID = CC.CNT_ID
inner JOIN dbo.WTMISS M ON CC.PER_ID = M.PER_ID AND CC.CNT_ID = M.CNT_ID
inner JOIN dbo.WTCNTI COT1 ON M.PER_ID = COT1.PER_ID AND M.CNT_ID = COT1.CNT_ID
inner JOIN dbo.WTQUAEU Q ON COT1.TIE_ID = Q.TIE_ID AND COT1.QEU_CDE = Q.QEU_CDE
inner JOIN dbo.WTSCCT C ON CC.RGPCNT_ID = C.RGPCNT_ID AND CC.PER_ID = C.PER_ID AND CC.CNT_ID = C.CNT_ID --AND''SECT3'' = C.STTQ_COD
INNER JOIN ##TempStaffT HF ON C.VAPO_CODE = HF.onetouch COLLATE Latin1_General_CI_AS
inner JOIN
##TempA AS p ON p.CNT_ID = COT1.CNT_ID inner JOIN
##TempB AS p1 ON p1.CNT_ID = COT1.CNT_ID
CROSS JOIN [dbo].[CustBusinessTable] CB
WHERE CB.[TempBusinessName]=''Pure Temp Fees''
GROUP BY p.CALF_AN,CB.[TempBusinessName]
'
;
PRINT #sql4;
My problem is that the query above took 20 min to be executed because ##TempStaffT contains too many rows , how can I optimize it ? I use many temp tables but it seems not to be worked , Any idea ? Many thanks in advance .

Create an index on ##TempStaffT
CREATE INDEX IDX_TempStaffT_onetouch ON ##TempStaffT(onetouch)

Related

Best Join Strategy/Indexes for SQL Server

What is the best join strategy/indexes for this query:
SELECT
kwk.*, an.AuftragDatum, an.AbgabeDatum, an.BezahltDatum, an.AuftragStatus
FROM
KundenWerbenKunden kwk
INNER JOIN
Auftrag an ON an.AuftragNummer = kwk.AuftragNummer
WHERE
kwk.Deleted = 0
Table KundenWerbenKunden has 103950 rows with 103646 Deleted = 0 ones.
Table Auftrag has 3826552 rows.
In my real query I make some more joins:
INNER JOIN
Filiale fn WITH (NOLOCK) ON an.FilialeID = fn.FilialeID
INNER JOIN
Kunde kn ON an.KundeID = kn.KundeID
OUTER APPLY
(SELECT DISTINCT KSKNr
FROM KdZuordnung
WHERE KundeID = kn.KundeID) zn
LEFT JOIN
Anrede ann WITH (NOLOCK) ON kn.Anrede = ann.Anrede
INNER JOIN
AuftragArt aa WITH (NOLOCK) ON an.AuftragArtID = aa.AuftragArtID
INNER JOIN
AuftragGrund ag WITH (NOLOCK) ON an.AuftragGrundID = ag.AuftragGrundID
INNER JOIN
AuftragType at WITH (NOLOCK) ON an.AuftragTypeID = at.AuftragTypeID
For this query:
SELECT *
FROM KundenWerbenKunden kwk INNER JOIN
Auftrag an
ON an.AuftragNummer = kwk.AuftragNummer
WHERE kwk.Geloescht = 0;
And not knowing anything about the distribution of Geloescht, I would first try indexes on KundenWerbenKunden(Geloescht, AuftragNummer) and Auftrag(AuftragNummer).

How to get rid of duplicating data in every row?

SELECT distinct AD.ReferenceNumber, AD.ProjectTitle, Z.ZoneCode, C.CompanyName,SS.AssignedTo, ZG.ZoneGroupName,au.Amount
FROM ApplicationDetails AD
LEFT JOIN ApplicationFormsDetails AS b ON (AD.referencenumber = b.referencenumber)
LEFT JOIN ScheduleSummaries AS SS ON (AD.ReferenceNumber = SS.ReferenceNo)
INNER JOIN AppTypes as at on ss.ItemCode = at.Category
INNER JOIN Companies AS C ON (AD.CompanyId = C.CompanyID)
INNER JOIN Zones Z ON (C.ZoneCode = Z.ZoneCode)
INNER JOIN ZoneGroups ZG ON (Z.ZoneGroup = ZG.ZoneGroupId)
LEFT JOIN AssessmentUsedItems au on ah.AssessmentHeaderId = au.HeaderId
WHERE AD.ApplicationDate BETWEEN '2017-10-01' AND '2017-10-31' AND ZG.ZoneGroupCode = 'HO' and ah.referencenumber = 'N-101317-A1-02'
GROUP BY AD.ReferenceNumber, AD.ProjectTitle, Z.ZoneCode, C.CompanyName,SS.AssignedTo, ZG.ZoneGroupName,au.Amount--, ah.ApplicationForm,au.Amount
The output of this query is its duplicating the amount for every AssignTO.
Output :
Maybe you want to try using SUM(ISNULL(au.amount, 0)) AS amount instead of au.amount and remove au.amount from the GROUP BY as well...
Try this query:
SELECT AD.ReferenceNumber,
AD.ProjectTitle,
Z.ZoneCode,
C.CompanyName,
SS.AssignedTo,
ZG.ZoneGroupName,
SUM(COALESCE(au.Amount,0)) AS Amount
FROM ApplicationDetails AD
LEFT JOIN ApplicationFormsDetails AS b
ON (AD.referencenumber = b.referencenumber)
LEFT JOIN ScheduleSummaries AS SS
ON (AD.ReferenceNumber = SS.ReferenceNo)
INNER JOIN AppTypes AS at
ON ss.ItemCode = at.Category
INNER JOIN Companies AS C
ON (AD.CompanyId = C.CompanyID)
INNER JOIN Zones Z
ON (C.ZoneCode = Z.ZoneCode)
INNER JOIN ZoneGroups ZG
ON (Z.ZoneGroup = ZG.ZoneGroupId)
LEFT JOIN AssessmentUsedItems au
ON ah.AssessmentHeaderId = au.HeaderId
WHERE AD.ApplicationDate BETWEEN '2017-10-01' AND '2017-10-31'
AND ZG.ZoneGroupCode = 'HO'
AND ah.referencenumber = 'N-101317-A1-02'
GROUP BY
AD.ReferenceNumber,
AD.ProjectTitle,
Z.ZoneCode,
C.CompanyName,
SS.AssignedTo,
ZG.ZoneGroupName

connot perform an aggregate function ... with GROUP BY

Hello i'm trying to write a query which consists to calculate the sum of 2 values, the second sum is result of multiplication between the first value and another. could someone help to solve this please ?? ( excuse me for my english, im frensh developer ) :
SELECT ISNULL(CONVERT(VARCHAR,CONVERT(date,MARE_DAT_CRE,103)),'Total') AS Dat
, SUM (MARE_CAUTIONNEMENT) AS HT
, SUM ( MARE_CAUTIONNEMENT * ( SELECT DISTINCT LCF_TAUXTVA
FROM F_LIGNECOMFOU
INNER JOIN F_AFFAIRES ON LCF_CODE_AFF = AF_CODE_AFFAIRE
INNER JOIN F_LOT ON LT_AFFAIRE = AF_CODE_AFFAIRE
INNER JOIN F_COMMANDEFOU ON CF_NUMERO = LCF_CF_NUMERO
INNER JOIN F_P_FOURNISSEUR ON CF_IDENT_FO = FOU_IDENT
WHERE AF_CODE_AFFAIRE = '15065-00' AND LT_IDENT = 500002200 AND FOU_IDENT = 500000838 ) ) FROM F_AVENANT_RETENUE INNER JOIN F_MARCHE_AVENANT ON MAAV_IDENT = MARE_MAAV_IDENT INNER JOIN F_MARCHE_TRAVAUX ON MATR_IDENT = MAAV_MATR_IDENT INNER JOIN F_AFFAIRES ON AF_CODE_AFFAIRE = MATR_AF_IDENT INNER JOIN F_LOT ON LT_AFFAIRE = AF_CODE_AFFAIRE INNER JOIN F_AVENANT_COTATION ON AVCO_IDENT = MARE_AVCO_IDENT WHERE AF_CODE_AFFAIRE = '15065-00' AND LT_IDENT = 500002200 AND MATR_FOU_IDENT = 500000838 AND MARE_CAUTIONNEMENT IS NOT NULL
GROUP BY MARE_DAT_CRE WITH ROLLUP
You could try sticking that sub select in your joins. Now you haven't used table alias so I'm not sure which tables contain the fields AF_CODE_AFFAIRE, LT_IDENT and MATR_FOU_IDENT so you'll have to add table aliases;
SELECT ISNULL(CONVERT(VARCHAR, CONVERT(DATE, MARE_DAT_CRE, 103)), 'Total') AS Dat
,SUM(MARE_CAUTIONNEMENT) AS HT
,SUM(MARE_CAUTIONNEMENT) * SUM(new.LCF_TAUXTVA)
FROM F_AVENANT_RETENUE
INNER JOIN F_MARCHE_AVENANT ON MAAV_IDENT = MARE_MAAV_IDENT
INNER JOIN F_MARCHE_TRAVAUX ON MATR_IDENT = MAAV_MATR_IDENT
INNER JOIN F_AFFAIRES ON AF_CODE_AFFAIRE = MATR_AF_IDENT
INNER JOIN F_LOT ON LT_AFFAIRE = AF_CODE_AFFAIRE
INNER JOIN F_AVENANT_COTATION ON AVCO_IDENT = MARE_AVCO_IDENT
LEFT JOIN (
SELECT DISTINCT LCF_TAUXTVA
FROM F_LIGNECOMFOU
INNER JOIN F_AFFAIRES ON LCF_CODE_AFF = AF_CODE_AFFAIRE
INNER JOIN F_LOT ON LT_AFFAIRE = AF_CODE_AFFAIRE
INNER JOIN F_COMMANDEFOU ON CF_NUMERO = LCF_CF_NUMERO
INNER JOIN F_P_FOURNISSEUR ON CF_IDENT_FO = FOU_IDENT
) new ON AF_CODE_AFFAIRE = new.AF_CODE_AFFAIRE
AND LT_IDENT = new.LT_IDENT
AND MATR_FOU_IDENT = new.MATR_FOU_IDENT
WHERE AF_CODE_AFFAIRE = '15065-00'
AND LT_IDENT = 500002200
AND MATR_FOU_IDENT = 500000838
AND MARE_CAUTIONNEMENT IS NOT NULL
GROUP BY ISNULL(CONVERT(VARCHAR, CONVERT(DATE, MARE_DAT_CRE, 103)), 'Total')
WITH ROLLUP

How can I use the group by Clause in a subquery

I just need to select one more field in my query that is the date... but it's a subquery and i'm using a count field... and because of it i need to use the GROUP BY Clause... But i can't group by my subquery and the query is returning errors...
SELECT
X.NROF,
Z.NMGUERFORN,
C.CDCOMPRADO,
C.CDCOORDENA,
E.CDFUP,
count(*) AS ocorrencias
--(select TOP 1 DTPROGENTR from CMPENL0 C (NOLOCK) where X.NRPEDICOMP = C.NRPEDICOMP AND X.NRITEMPECO = C.NRITEMPECO) AS DTPROGENTR
FROM CMPCIL0 X (NOLOCK)
inner join CMPCCL0 Y (NOLOCK) on X.NRPEDICOMP = Y.NRPEDICOMP
inner join CMFRNL0 Z (NOLOCK) on Y.CDFORNECED1 = Z.CDFORNECED1
inner join CMSCPL0 M (NOLOCK) on X.NRSOLICOMP = M.NRSOLICOMP AND X.NRITEMSC = M.NRITEMSC
inner join CMPENL0 N (NOLOCK) on X.NRPEDICOMP = N.NRPEDICOMP AND X.NRITEMPECO = N.NRITEMPECO
inner join CMMATL0 A (NOLOCK) on X.CDMATERIAL = A.CDMATERIAL
inner join cmcomL0 c (NOLOCK) on c.cdcomprado = y.cdcomprado
LEFT JOIN AMCSPL0 D (NOLOCK) ON D.SCPE_NRSOLICOMP = X.NRSOLICOMP AND D.SCPE_NRITEMSC=X.NRITEMSC
LEFT JOIN CMFUPL0 E (NOLOCK) ON E.CDFORNECED1 = Z.CDFORNECED1
LEFT JOIN CMPFIL0 H ON Z.CDFORNECED1 = H.CDFORNECED1 AND X.NRIDENTIFI = H.NRIDENTIFI and H.DTVALIDADE > Y.DTEFETPECO
LEFT JOIN CMPENL0 F ON (X.NRPEDICOMP = F.NRPEDICOMP AND X.NRITEMPECO = F.NRITEMPECO)
WHERE X.CDSTATUS = 'P' and X.NROF <> 0
group by X.NROF,Z.NMGUERFORN,C.CDCOMPRADO,C.CDCOORDENA,E.CDFUP--,DTPROGENTR
order by 6 desc
The commented parts are the code im trying to include to select the field, but it is giving me errors..
The problem is that you use aliases in your where clause of select sub-query. Aliases cannot be referenced on the same level in the query. You should use full qualified names and the sub-query should look something like that:
(select TOP 1 DTPROGENTR from CMPENL0 C (NOLOCK) where X.NRPEDICOMP = CMPENL0.NRPEDICOMP AND X.NRITEMPECO = CMPENL0.NRITEMPECO) AS DTPROGENTR
If your sql-server supports common table expressions you can try that:
;WITH cte AS
(
SELECT ROW_NUMBER() OVER(PARTITION BY NRPEDICOMP, NRITEMPECO ORDER BY NRPEDICOMP) row_num
,DTPROGENTR
,NRPEDICOMP
,NRITEMPECO
FROM CMPENL0 (NOLOCK)
)
SELECT
X.NROF,
Z.NMGUERFORN,
C.CDCOMPRADO,
C.CDCOORDENA,
E.CDFUP,
count(*) AS ocorrencias
cte.DTPROGENTR
FROM CMPCIL0 X (NOLOCK)
inner join CMPCCL0 Y (NOLOCK) on X.NRPEDICOMP = Y.NRPEDICOMP
inner join CMFRNL0 Z (NOLOCK) on Y.CDFORNECED1 = Z.CDFORNECED1
inner join CMSCPL0 M (NOLOCK) on X.NRSOLICOMP = M.NRSOLICOMP AND X.NRITEMSC = M.NRITEMSC
inner join CMPENL0 N (NOLOCK) on X.NRPEDICOMP = N.NRPEDICOMP AND X.NRITEMPECO = N.NRITEMPECO
inner join CMMATL0 A (NOLOCK) on X.CDMATERIAL = A.CDMATERIAL
inner join cmcomL0 c (NOLOCK) on c.cdcomprado = y.cdcomprado
LEFT JOIN AMCSPL0 D (NOLOCK) ON D.SCPE_NRSOLICOMP = X.NRSOLICOMP AND D.SCPE_NRITEMSC=X.NRITEMSC
LEFT JOIN CMFUPL0 E (NOLOCK) ON E.CDFORNECED1 = Z.CDFORNECED1
LEFT JOIN CMPFIL0 H ON Z.CDFORNECED1 = H.CDFORNECED1 AND X.NRIDENTIFI = H.NRIDENTIFI and H.DTVALIDADE > Y.DTEFETPECO
LEFT JOIN CMPENL0 F ON X.NRPEDICOMP = F.NRPEDICOMP AND X.NRITEMPECO = F.NRITEMPECO
LEFT JOIN cte ON X.NRPEDICOMP = cte.NRPEDICOMP AND X.NRITEMPECO = cte.NRITEMPECO AND cte.row_num = 1
WHERE X.CDSTATUS = 'P' and X.NROF <> 0
group by X.NROF,Z.NMGUERFORN,C.CDCOMPRADO,C.CDCOORDENA,E.CDFUP, cte.DTPROGENTR
order by 6 desc

MSSQL How do I get average of four records from different tables?

I have four tables and I need to find the average of each score for a particular id. I do not need the ENTIRE Column average, but the average of each record with the same id in each table.
I have tried this:
SELECT DISTINCT M.system_id, S.name, SUM(A.Score + WAL.score + F.score + WIN.score) / 4
AS avgScore
FROM dbo.T3_MovementSystemJoin AS M
INNER JOIN dbo.T3_systems AS S ON M.system_id = S.id
INNER JOIN T3_ApplicationSystemJoin AS A ON A.Application_id = #application_id
INNER JOIN T3_WallTypeSystemJoin AS WAL ON WAL.wall_id = #wall_id
INNER JOIN T3_FenestrationSystemJoin AS F ON F.fenestration_id = #fen_id
INNER JOIN T3_WindowOrientation_System AS WIN ON WIN.window_id = #window_id
INNER JOIN T3_ConstructionSystemJoin AS C ON C.contruction_id = #construction_id
INNER JOIN T3_JointDepthSystemJoin AS J ON J.JointDepth_id = #JointDepth_id
INNER JOIN T3_JointGapSystemJoin AS JG ON JG.JointGap_id = #JointGap_id
WHERE (M.movement_id = #movement_id)
GROUP BY M.System_id, S.name
:
Thanks for your help!
No Sum needed (and no grouping too)
SELECT DISTINCT M.system_id, S.name, (IsNull(A.Score, 0) + IsNull(WAL.score, 0) + IsNull(F.score, 0) + IsNull(WIN.score, 0)) /4
as avgscore
FROM dbo.T3_MovementSystemJoin AS M
INNER JOIN dbo.T3_systems AS S ON M.system_id = S.id
INNER JOIN T3_ApplicationSystemJoin AS A ON A.Application_id = #application_id
INNER JOIN T3_WallTypeSystemJoin AS WAL ON WAL.wall_id = #wall_id
INNER JOIN T3_FenestrationSystemJoin AS F ON F.fenestration_id = #fen_id
INNER JOIN T3_WindowOrientation_System AS WIN ON WIN.window_id = #window_id
INNER JOIN T3_ConstructionSystemJoin AS C ON C.contruction_id = #construction_id
INNER JOIN T3_JointDepthSystemJoin AS J ON J.JointDepth_id = #JointDepth_id
INNER JOIN T3_JointGapSystemJoin AS JG ON JG.JointGap_id = #JointGap_id
WHERE (M.movement_id = #movement_id)
SELECT DISTINCT M.system_id
,S.name
,(ISNULL(A.Score,0) + ISNULL(WAL.score,0) + ISNULL(F.score,0) + ISNULL(WIN.score,0)) /4 as 'AvgScore'
FROM dbo.T3_MovementSystemJoin AS M
INNER JOIN dbo.T3_systems AS S ON M.system_id = S.id
INNER JOIN T3_ApplicationSystemJoin AS A ON A.Application_id = #application_id
INNER JOIN T3_WallTypeSystemJoin AS WAL ON WAL.wall_id = #wall_id
INNER JOIN T3_FenestrationSystemJoin AS F ON F.fenestration_id = #fen_id
INNER JOIN T3_WindowOrientation_System AS WIN ON WIN.window_id = #window_id
INNER JOIN T3_ConstructionSystemJoin AS C ON C.contruction_id = #construction_id
INNER JOIN T3_JointDepthSystemJoin AS J ON J.JointDepth_id = #JointDepth_id
INNER JOIN T3_JointGapSystemJoin AS JG ON JG.JointGap_id = #JointGap_id
WHERE (M.movement_id = #movement_id)
If you don't want NULL values to become zeros and included in the average:
SELECT DISTINCT M.system_id, S.name, X.avgScore
FROM dbo.T3_MovementSystemJoin AS M
INNER JOIN dbo.T3_systems AS S ON M.system_id = S.id
INNER JOIN T3_ApplicationSystemJoin AS A ON A.Application_id = #application_id
INNER JOIN T3_WallTypeSystemJoin AS WAL ON WAL.wall_id = #wall_id
INNER JOIN T3_FenestrationSystemJoin AS F ON F.fenestration_id = #fen_id
INNER JOIN T3_WindowOrientation_System AS WIN ON WIN.window_id = #window_id
INNER JOIN T3_ConstructionSystemJoin AS C ON C.contruction_id = #construction_id
INNER JOIN T3_JointDepthSystemJoin AS J ON J.JointDepth_id = #JointDepth_id
INNER JOIN T3_JointGapSystemJoin AS JG ON JG.JointGap_id = #JointGap_id
CROSS APPLY ( SELECT AVG(s) FROM (VALUES (A.Score),(WAL.score),(F.score),(WIN.score) ) scores(s) ) X(avgScore)
WHERE (M.movement_id = #movement_id)
GROUP BY M.System_id, S.name