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

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.

Related

Add the correct condition in WHERE statement using CASE

It's been months since I explore SQL Server but I am still new to this field. I need to output rows that will return ISBLANK = 0 or ISBLANK IS NULL. I am using CASE statement.
Expected output:
My code:
SELECT UD.FID
, UD.UID
, CBH.BID
, FBA.ISBLANK
FROM TEMP_UD UD
INNER JOIN TBL_CBH CBH
ON UD.FID = CBH.FID
INNER JOIN TBL_UDF UDF
ON UDF.FID = UDF.FID
LEFT JOIN TBL_FBA FBA
ON FBA.FID = CBH.FID
AND FBA.BID = CBH.BID
WHERE
(
CASE
WHEN UDF.COND = 10 AND UDF.UID = 12 AND FBA.ISBLANK != 1
THEN 0
END = FBA.ISBLANK
)
Current output:
FID UID BID ISBLANK
-------------------
1 12 1 0
1 12 1 0
Sample code:
https://onecompiler.com/mysql/3y29djktg
Try:
CASE WHEN UDF.COND = 10
AND UDF.UID = 12
AND FBA.ISBLANK = 1
THEN 1
ELSE 0
END = 1
This will/should return the rows where ISBLANK 1 1 does not apply.
I am wondering why you are not using the conditions directly in the WHERE, like this:
WHERE UDF.COND = 10
AND UDF.UID = 12
AND ( FBA.ISBLANK IS NULL OR FBA.ISBLANK = 0 )
If any optimizations can be made based on the columns that are used, they cannot be made if they are used in a CASE expression.

Select Records Expert equivalent for SSRS

Crystal Reports has the Select Records Expert which allows you to use variables to build WHERE conditions. Is there something similar to the select records experts in SSRS?
If the variable #Restriction below is equal to one, the column name CFE_EDI.ETAT = 'ENV' or CFE_EDI.ETAT = 'OUV'. I tried to mimic the functionality with a SQL query but due to AND and OR precedence, the WHERE condition is not functioning properly.
You can handle this within the SQL of your SSRS Dataset where clause buy using case statements that return a 1 or a 0 depending on whether or not the criteria is met:
where case when #Restriction = '1'
then case when CFE_EDI.ETAT in('ENV','OUV') then 1 else 0 end
when #Restriction = '0'
then case when CFE_EDI.ETAT not in('ENV','OUV') then 1 else 0 end
else case when CFE_EDI.ETAT <> '' then 1 else 0 end
end = 1

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)

SELECT IF into custom variable

I have this:
SELECT
#is_daily_rollup = CASE WHEN rt.[id]=1 THEN 1 ELSE 0,
#is_weekly_rollup = CASE WHEN rt.[id]=2 THEN 1 ELSE 0
But sql server is complaining about syntax. How would I go about implementing this conditional value into a variable?
For a CASE statement you need to provide an END
CASE WHEN rt.[id]=1 THEN 1 ELSE 0 END
CASE WHEN rt.[id]=2 THEN 1 ELSE 0 END
so your full query would be:
SELECT #is_daily_rollup = CASE WHEN rt.[id]=1 THEN 1 ELSE 0 END,
#is_weekly_rollup = CASE WHEN rt.[id]=2 THEN 1 ELSE 0 END
You are missing the END for your CASE:
SELECT
#is_daily_rollup = CASE WHEN rt.[id]=1 THEN 1 ELSE 0 END,
#is_weekly_rollup = CASE WHEN rt.[id]=2 THEN 1 ELSE 0 END
Of course, this is assuming that you already declared yor variables.

How to get all values including null in a SQL Server case statement?

I have a big stored procedure, and basically I want to select all values (including null) if my variable #DimBrowserId is set to 0. I am using a case statement, however this is only catching values that actually have something and ignoring the NULL valued fields. Because I am using the = clause in the WHERE I cannot do IS NULL. I do not want to have to write 2 IF statements because the stored procedure would then be enormous, so I want to know how to get null values as well. Here is my code:
SELECT
DATEPART(yy, DATEADD(mi, #Mdelta, d.DimDateValue)),
DisableCount = COUNT(*)
FROM
dbo.FactDisable AS f
JOIN
dbo.DimDate AS d ON f.DimDateId = d.DimDateId
JOIN
dbo.DimDevice AS v ON f.DimDeviceId = v.DimDeviceId
WHERE
d.DimDateValue >= #StartDateGMT
AND d.DimDateValue <= #EndDateGMT
AND f.IsTest = #IncludeTest
AND f.DimProductId = #DimProductId
AND v.DimBrowserId = CASE
WHEN #DimBrowserId = 0 THEN v.DimBrowserId
ELSE #DimBrowserId
END
GROUP BY
DATEPART(yy, DATEADD(mi, #Mdelta, d.DimDateValue))
The code is near the CASE clause.
Thanks
Change that line to be
AND (#DimBrowserID = 0 OR #DimBrowserID = v.DimBrowserId)
If #DimBroserID is 0 then no filtering will be applied for this line.
Use ISNULL:
SELECT DATEPART(yy,DATEADD(mi,#Mdelta,d.DimDateValue)),
DisableCount=COUNT(*)
FROM dbo.FactDisable AS f
JOIN dbo.DimDate AS d ON f.DimDateId = d.DimDateId
JOIN dbo.DimDevice AS v ON f.DimDeviceId = v.DimDeviceId
WHERE d.DimDateValue >= #StartDateGMT AND d.DimDateValue <= #EndDateGMT
AND f.IsTest = #IncludeTest AND f.DimProductId = #DimProductId
AND v.DimBrowserId = CASE WHEN ISNULL(#DimBrowserId,0) = 0 THEN v.DimBrowserId ELSE #DimBrowserId END
GROUP BY DATEPART(yy,DATEADD(mi,#Mdelta,d.DimDateValue))
CASE WHEN COALESCE(#MightBeNull, 0) = 0 THEN ZeroResult ...
will be treated as zero if #MightBeNull is null, and whatever #MightBeNull is if it's not null.
Assuming null means any browser, a better data model for this scenario might be to set an ID that identifies any browser, instead of setting it to null.
You probably know what you are running into is NULL does not equal NULL in a comparison.
Assuming you don't have control of the data model to fix that, one option would be to coalesce your NULL values to an unused id.
The resulting WHERE clause would look like this, assuming -1 is the unused value you choose.
AND COALESCE(v.DimBrowserId, -1) = CASE WHEN #DimBrowserId = 0 THEN COALESCE(v.DimBrowserId, -1) ELSE #DimBrowserId END

Resources