How can I optimize the SQL query? - sql

I have a query an SQL query as follows, can anybody suggest any optimization for this; I think most of the effort is being done for the Union operation - is there anything else can be done to get the same result ?
Basically I wanna query first portion of the UNION and if for each record there is no result then the second portion need to be run. Please help.
:
SET dateformat dmy;
WITH incidentcategory
AS (
SELECT 1 ord, i.IncidentId, rl.Description Category FROM incident i
JOIN IncidentLikelihood l ON i.IncidentId = l.IncidentId
JOIN IncidentSeverity s ON i.IncidentId = s.IncidentId
JOIN LikelihoodSeverity ls ON l.LikelihoodId = ls.LikelihoodId AND s.SeverityId = ls.SeverityId
JOIN RiskLevel rl ON ls.RiskLevelId = rl.riskLevelId
UNION
SELECT 2 ord, i.incidentid,
rl.description Category
FROM incident i
JOIN incidentreportlikelihood l
ON i.incidentid = l.incidentid
JOIN incidentreportseverity s
ON i.incidentid = s.incidentid
JOIN likelihoodseverity ls
ON l.likelihoodid = ls.likelihoodid
AND s.severityid = ls.severityid
JOIN risklevel rl
ON ls.risklevelid = rl.risklevelid
) ,
ic AS (
SELECT ROW_NUMBER() OVER (PARTITION BY i.IncidentId ORDER BY (CASE WHEN incidentTime IS NULL THEN GETDATE() ELSE incidentTime END) DESC,ord ASC) rn,
i.incidentid,
dbo.Incidentdescription(i.incidentid, '',
'',
'', '')
IncidentDescription,
dbo.Dateconverttimezonecompanyid(closedtime,
i.companyid)
ClosedTime,
incidenttime,
incidentno,
Isnull(c.category, '')
Category,
opencorrectiveactions,
reportcompleted,
Isnull(classificationcompleted, 0)
ClassificationCompleted,
Cast (( CASE
WHEN closedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
IncidentClosed,
Cast (( CASE
WHEN investigatorfinishedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationFinished,
Cast (( CASE
WHEN investigationcompletetime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigationComplete,
Cast (( CASE
WHEN investigatorassignedtime IS NULL THEN 0
ELSE 1
END ) AS BIT)
InvestigatorAssigned,
Cast (( CASE
WHEN (SELECT Count(*)
FROM incidentinvestigator
WHERE incidentid = i.incidentid
AND personid = 1588
AND tablename = 'AdminLevels') = 0
THEN 0
ELSE 1
END ) AS BIT)
IncidentInvestigator,
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader,
incidentstatus,
incidentstatussearch
FROM incident i
LEFT OUTER JOIN incidentcategory c
ON i.incidentid = c.incidentid
WHERE i.isdeleted = 0
AND i.companyid = 158
AND incidentno <> 0
--AND reportcompleted = 1
--AND investigatorassignedtime IS NOT NULL
--AND investigatorfinishedtime IS NULL
--AND closedtime IS NULL
),
ic2 AS (
SELECT * FROM ic WHERE rn=1
)
SELECT * FROM ic2
--WHERE rownumber >= 0
-- AND rownumber < 0 + 10
--WHERE ic2.incidentid in(53327,53538)
--WHERE ic2.incidentid = 53338
ORDER BY incidentid DESC
Following is the execution plan I got:
https://www.dropbox.com/s/50dcpelr1ag4blp/Execution_Plan.sqlplan?dl=0

There are several issues:
1) use UNION ALL instead of UNION ALL to avoid the additional operation to aggregate the data.
2) try to modify the numerous function calls (e.g. dbo.Incidentdescription() ) to be an in-lie table valued function so you can reference it using CROSS APPLY or OUTER APPLY. Especially, if those functions referencing a table again.
3) move the subqueries from the SELECT part of the query to the FROM part using CROSS APPLY or OUTER APPLY again.
4) after the above is done, check the execution plan again for any missing indexes. Also, run the query with STATISTICS TIME, IO on to verify that the number of times a table
is referenced is correct (sometimes the execution plan put you in the wrong direction, especially if function calls are involved)...

Since the first inner query produces rows with ord=1 and the second produces rows with ord=2, you should use UNION ALL instead of UNION. UNION will filter out equal rows and since you will never get equal rows it is more efficient to use UNION ALL.
Also, rewrite your query to not use the WITH construct. I've had very bad experiences with this. Just use regular derived tables instead. In the case the query is still abnormally slow, try to serialize some derived tables to a temporary table and query the temporary table instead.

Try alternate approach by removing
(SELECT dbo.Strconcat(osname)
FROM (SELECT TOP 10 osname
FROM incidentlocation l
JOIN organisationstructure o
ON l.locationid = o.osid
WHERE incidentid = i.incidentid
ORDER BY l.locorder) loc)
Location,
Isnull((SELECT TOP 1 teamleader
FROM incidentinvestigator
WHERE personid = 1588
AND tablename = 'AdminLevels'
AND incidentid = i.incidentid), 0)
TeamLeader
from the SELECT. Avoid using complex functions/sub-queries in select.

Related

CTE TABLE WITH ORDER BY ERROR MESSAGE SQL SERVER

;WITH myTree AS
(
SELECT
y.User_id, y.user_usercode, y.user_username,
y.user_uplineID,
trans_WinLose, y.User_ID AS sourceID, trans_id,
trans_Rolling, y.User_Level,
lvl1.User_Level AS Level_lvl1, lvl2.User_Level AS Level_lvl2,
y.User_GivenPT, lvl1.User_GivenPT AS GivenPT_lvl1,
lvl2.User_GivenPT AS GivenPT_lvl2, y.User_GivenComm,
lvl1.User_GivenComm AS downline_Comm
FROM
tbl_user y
INNER JOIN
tbl_trans x ON x.trans_Robot_ID = y.User_RobotID
INNER JOIN
tbl_user lvl1 ON y.user_uplineID = lvl1.User_ID
INNER JOIN
tbl_user lvl2 ON lvl1.user_uplineID = lvl2.User_ID
UNION ALL
SELECT
u.User_ID, u.user_usercode, u.user_username, u.user_uplineID,
t.trans_WinLose, t.sourceID AS sourceID, t.trans_Id,
t.trans_Rolling, u.User_Level, t.User_Level, t.Level_lvl1,
u.User_GivenPT, t.User_GivenPT, t.GivenPT_lvl1,
u.User_GivenComm, t.User_GivenComm
FROM
myTree t
INNER JOIN
tbl_user u ON t.user_uplineID = u.User_ID
)
SELECT *
FROM
(SELECT
mytree.*,
(SELECT
CASE
WHEN Level_lvl1 = 7 THEN GivenPT_lvl1
WHEN level_lvl2 = 7 THEN User_GivenPT-GivenPT_Lvl2
ELSE (CASE
WHEN (User_GivenPT-GivenPT_lvl1) > 0
THEN User_GivenPT - GivenPT_lvl1
ELSE 0
END)
END) AS Net_PT
FROM
Mytree
ORDER BY
mytree.trans_ID) AS c
I would like to order by mytree.trans_ID, but I get an error:
Msg 1033, Level 15, State 1, Line 17
The ORDER BY clause is invalid in views, inline functions, derived tables, subqueries, and common table expressions, unless TOP, OFFSET or FOR XML is also specified.
How to solve this problem?
Another possibility is to remove the outer query when querying the CTE - it doesn't seem to serve any purpose.
;with myTree as (
select y.User_id,y.user_usercode,y.user_username,y.user_uplineID,trans_WinLose, y.User_ID as sourceID, trans_id,trans_Rolling,y.User_Level,lvl1.User_Level as Level_lvl1,lvl2.User_Level as Level_lvl2,y.User_GivenPT,lvl1.User_GivenPT as GivenPT_lvl1 ,lvl2.User_GivenPT as GivenPT_lvl2,y.User_GivenComm,lvl1.User_GivenComm as downline_Comm from tbl_user y
Inner join tbl_trans x on x.trans_Robot_ID = y.User_RobotID
Inner join tbl_user lvl1 on y.user_uplineID = lvl1.User_ID
Inner join tbl_user lvl2 on lvl1.user_uplineID = lvl2.User_ID
union all
select u.User_ID,u.user_usercode,u.user_username,u.user_uplineID,t.trans_WinLose, t.sourceID as sourceID, t.trans_Id,t.trans_Rolling,u.User_Level,t.User_Level,t.Level_lvl1,u.User_GivenPT,t.User_GivenPT,t.GivenPT_lvl1,u.User_GivenComm,t.User_GivenComm
from myTree t
inner join tbl_user u on t.user_uplineID = u.User_ID
)
SELECT mytree.*,
(SELECT CASE
WHEN Level_lvl1=7 THEN GivenPT_lvl1
WHEN level_lvl2=7 THEN User_GivenPT-GivenPT_Lvl2
ELSE (CASE WHEN (User_GivenPT-GivenPT_lvl1) > 0 THEN User_GivenPT-GivenPT_lvl1 else 0 END)
END) as Net_PT
From Mytree order by mytree.trans_ID
SQL behaves with data in Mathematics Sets manner. In Sets the order of data and elements are meaningless. So when you are dealing with CTE, sub-queries, views, inline table value functions etc, that are used to return a set of data, you are not allowed to order and sort them.
You need to sort data when you need to show them in output or you are using TOP or OFFSET-Fetch or etc commands, where the Order By helps these commands to work as they should be.
You should rewrite your query as:
;with myTree as (
select y.User_id,y.user_usercode,y.user_username,y.user_uplineID,trans_WinLose, y.User_ID as sourceID, trans_id,trans_Rolling,y.User_Level,lvl1.User_Level as Level_lvl1,lvl2.User_Level as Level_lvl2,y.User_GivenPT,lvl1.User_GivenPT as GivenPT_lvl1 ,lvl2.User_GivenPT as GivenPT_lvl2,y.User_GivenComm,lvl1.User_GivenComm as downline_Comm from tbl_user y
Inner join tbl_trans x on x.trans_Robot_ID = y.User_RobotID
Inner join tbl_user lvl1 on y.user_uplineID = lvl1.User_ID
Inner join tbl_user lvl2 on lvl1.user_uplineID = lvl2.User_ID
union all
select u.User_ID,u.user_usercode,u.user_username,u.user_uplineID,t.trans_WinLose, t.sourceID as sourceID, t.trans_Id,t.trans_Rolling,u.User_Level,t.User_Level,t.Level_lvl1,u.User_GivenPT,t.User_GivenPT,t.GivenPT_lvl1,u.User_GivenComm,t.User_GivenComm
from myTree t
inner join tbl_user u on t.user_uplineID = u.User_ID
)select * from (SELECT mytree.*,
(SELECT CASE
WHEN Level_lvl1=7 THEN GivenPT_lvl1
WHEN level_lvl2=7 THEN User_GivenPT-GivenPT_Lvl2
ELSE (CASE WHEN (User_GivenPT-GivenPT_lvl1) > 0 THEN User_GivenPT-GivenPT_lvl1 else 0 END)
END) as Net_PT
From Mytree) as c
order by c.trans_ID
From Mytree order by mytree.trans_ID OFFSET 0 ROWS
change it to this, solved

How can I get value from above row with same ID if row is null?

I'm new with SQL and I encountered this.
Here's a screenshot
My question is how can I make all the NULL on primary_payer_id get the value above only if they have same ClientID and ActionCode IS NOT NULL. FYI CustomColumn is only a copy of primary_payer_id ALSO I attached my code here below.
Here's my code:
SELECT ci.client_id AS ClientID,
ci.primary_payer_id,
ci.effective_date AS EffectiveDate,
ci.action_code_id AS ActionCode,
cc.item_description AS ItemDesc,
ap.description AS IDescription,
ci.deleted
FROM census_item ci
LEFT JOIN common_code cc ON ci.adt_tofrom_id = cc.item_id
LEFT JOIN ar_lib_payers ap ON ci.primary_payer_id = ap.payer_id
WHERE ci.deleted = 'N'
There might be a more efficient method, but this will work:
with t as (
<your query here>
)
select t.*,
(case when t.actioncode is not null and t.clientid is null
then tprev.clientid
else t.clientid
end) as new_clientid
from t outer apply
(select top 1 tprev.*
from t tprev
where tprev.clientid = t.clientid and
tprev.effectivedate < t.effectivedate
order by tprev.effecctivedate desc
) tprev;

Sum of resulting set of rows in SQL

I've got the following query:
SELECT DISTINCT CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
/*MC.chemical_percentage,*/
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
--AND CU.permit_id = 2118
--GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month, MC.chemical_id, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound
--ORDER BY C.chemical_name ASC
Which returns:
But what I need is to return one row per month per material adding up the values of POC per month and NON_POC per month.
So, I should end up with something like:
Month material_id material_name POC NON_POC
1 52 Krylon... 0.107581 0.074108687
2 52 Krylon... 0.143437 0.0988125
I tried using SUM but it sums up the same result multiple times:
SELECT /*DISTINCT*/ CU.permit_id, CU.month, /*CU.year,*/ M.material_id, M.material_name, /*MC.chemical_id, C.chemical_name,
C.precursor_organic_compound, C.non_precursor_organic_compound,*/
--MC.chemical_percentage,
POC_emissions = SUM(
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END),
NON_POC_emissions = SUM(
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END)
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE M.material_id = 52
--AND CU.permit_id = 187
AND (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
GROUP BY CU.permit_id, M.material_id, M.material_name, CU.month/*, CU.year, MC.chemical_id, C.chemical_name, C.precursor_organic_compound, C.non_precursor_organic_compound*/
--ORDER BY C.chemical_name ASC
The first query has a DISTINCT clause. What is the output without the DISTINCT clause. I suspect you have more rows than shows in your screenshot.
Regardless, you could try something like this to get the desired result.
select permit_id, month, material_id, material_name,
sum(poc_emissions), sum(non_poc_emissions)
from (
SELECT DISTINCT CU.permit_id, CU.month, M.material_id, M.material_name,
POC_emissions =
CASE
WHEN (C.precursor_organic_compound = 'true')
THEN (CU.chemical_usage_lbs / CU.material_density) * M.VOC
ELSE 0
END,
NON_POC_emissions =
CASE
WHEN (C.non_precursor_organic_compound = 'true')
THEN CU.chemical_usage_lbs * (MC.chemical_percentage / 100)
ELSE 0
END
FROM material M
LEFT OUTER JOIN material_chemical MC ON MC.material_id = M.material_id
LEFT OUTER JOIN chemical_usage CU ON CU.material_id = MC.material_id
LEFT OUTER JOIN chemical C ON C.chemical_id = MC.chemical_id
WHERE (CU.month >=1 AND CU.month <= 2)
AND CU.year = 2013
AND M.material_id = 52
) main
group by permit_id, month, material_id, material_name
Explanation
Since the results you retrieved by doing a DISTINCT was consider source-of-truth, I created an in-memory table by making it a sub-query. However, this subquery must have a name of some kind...whatever name. I gave it a name main. Subqueries look like this:
select ... from (sub-query) <give-it-a-table-name>
Simple Example:
select * from (select userid, username from user) user_temp
Advanced Example:
select * from (select userid, username from user) user_temp
inner join (select userid, sum(debits) as totaldebits from debittable) debit
on debit.userid = user_temp.userid
Notice how user_temp alias for the subquery can be used as if the sub-query was a real table.
Use above query in subquery and group by (month) and select sum(POC_emissions) and sum(NON_POC_emissions )

Mysql optimization for select query with IN() clause inside where clause (explain output given)

I have this query:-
SELECT SUM(DISTINCT( ttagrels.id_tag IN ( 1816, 2642, 1906, 1398,
2436, 2940, 1973, 2791, 1389 ) )) AS
key_1_total_matches,
IF(( od.id_od > 0 ), COUNT(DISTINCT( od.id_od )), 0) AS
tutor_popularity,
td.*,
u.*
FROM tutor_details AS td
JOIN users AS u
ON u.id_user = td.id_user
JOIN all_tag_relations AS ttagrels
ON td.id_tutor = ttagrels.id_tutor
LEFT JOIN learning_packs AS lp
ON ttagrels.id_lp = lp.id_lp
LEFT JOIN learning_packs_categories AS lpc
ON lpc.id_lp_cat = lp.id_lp_cat
LEFT JOIN learning_packs_categories AS lpcp
ON lpcp.id_lp_cat = lpc.id_parent
LEFT JOIN learning_pack_content AS lpct
ON ( lp.id_lp = lpct.id_lp )
LEFT JOIN webclasses AS wc
ON ttagrels.id_wc = wc.id_wc
LEFT JOIN learning_packs_categories AS wcc
ON wcc.id_lp_cat = wc.id_wp_cat
LEFT JOIN learning_packs_categories AS wccp
ON wccp.id_lp_cat = wcc.id_parent
LEFT JOIN order_details AS od
ON td.id_tutor = od.id_author
LEFT JOIN orders AS o
ON od.id_order = o.id_order
WHERE ( u.country = 'IE'
OR u.country IN ( 'INT' ) )
AND u.status = 1
AND CASE
WHEN ( lp.id_lp > 0 ) THEN lp.id_status = 1
AND lp.published = 1
AND lpcp.status = 1
AND ( lpcp.country_code = 'IE'
OR lpcp.country_code IN ( 'INT' )
)
ELSE 1
END
AND CASE
WHEN ( wc.id_wc > 0 ) THEN wc.wc_api_status = 1
AND wc.id_status = 1
AND wc.wc_type = 0
AND
wc.class_date > '2010-06-16 11:44:40'
AND wccp.status = 1
AND ( wccp.country_code = 'IE'
OR wccp.country_code IN ( 'INT' )
)
ELSE 1
END
AND CASE
WHEN ( od.id_od > 0 ) THEN od.id_author = td.id_tutor
AND o.order_status = 'paid'
AND CASE
WHEN ( od.id_wc > 0 ) THEN od.can_attend_class = 1
ELSE 1
END
ELSE 1
END
AND ( ttagrels.id_tag IN ( 1816, 2642, 1906, 1398,
2436, 2940, 1973, 2791, 1389 ) )
GROUP BY td.id_tutor
HAVING key_1_total_matches = 1
ORDER BY tutor_popularity DESC,
u.surname ASC,
u.name ASC
LIMIT 0, 20
The numbers inside the IN() are actually ids of another table called Tags which matched the search keywords entered by users. In this example the user has searched "class".
See the explain output of this query here:-
http://www.test.examvillage.com/Screenshot.png
The time taken by this query is 0.0536 sec
But, if the number of values in the ttagrels.id_tag in () increases (as user enters more search keywords), the execution time rises to around 1-5 seconds and more.For example, if user searched "class Available to tutors and students 3 times a day"
the execution time is 4.2226 sec. The explain query output for this query contains 2513 under rows.
There are a total of 6,152 records in the All_Tag_Relations table. Is any further optimization possible?
I don't know your databse, so I cannot give a definitive answer.
I notice in your query the Distinct keyword twice SUM(DISTINCT( and COUNT(DISTINCT(
This implies that your select statement returns several rows with the same id_tag or id_od. This means that your intermediate result before grouping contains to many rows. You must narrow down your where clauses to limit the rows.
Insert count(*) in your query, and observe the number of rows. If it is larger than expected, this explains your problem.

Query I need to be sped up

I have this query in SQL Server 2005:
SELECT J.JobID,
dbo.tblCustomers.Name AS CustomerName,
J.CustomerJobNumber,
J.JobName,
(CASE WHEN [tblCustomers].[CoreCust] = 0 THEN 'AUXILIARY' ELSE 'CORE' END) AS Department,
J.JobStatusID,
dbo.tblJobTypes.JobType
FROM dbo.tblJobs (NOLOCK) AS J
INNER JOIN dbo.tblCustomers (NOLOCK) ON J.CustomerID = dbo.tblCustomers.CustomerID
INNER JOIN dbo.tblJobTypes (NOLOCK) ON J.JobTypeID = dbo.tblJobTypes.JobTypeID
INNER JOIN dbo.tblDepartments (NOLOCK) ON J.DepartmentId = dbo.tblDepartments.DepartmentID
WHERE (J.Closed = 0)
AND (J.Invoiced = 0)
AND (J.Active = 1)
AND (dbo.fncIsAllPointsDelivered(J.JobID) = 1)
AND (J.DepartmentId <> 2)
This query is taking too long to run, and I know the problem is the UDF - (dbo.fncIsAllPointsDelivered(J.JobID) = 1) -.
The SQL for the UDF is here:
DECLARE #DetailCount int
DECLARE #TrackingCount int
SELECT #DetailCount = COUNT(*)
FROM [dbo].[tblLoadDetails] (NOLOCK)
WHERE JobId = #JobId
SELECT #TrackingCount = COUNT(*)
FROM [dbo].[tblLoadDetails] (NOLOCK)
WHERE JobId = #JobId AND Delivered = 1
IF(#DetailCount = #TrackingCount AND #DetailCount > 0)
RETURN 1
RETURN 0
All of this runs blazingly fast unless the job has a large number of load details in it. I am trying to think of a way to either make the UDF faster or get rid of the need for the UDF, but I am at a loss. I am hoping some of you SQL gurus will be able to help me.
SELECT *
FROM tblJobs j
INNER JOIN
tblCustomers c
ON c.CustomerID = J.CustomerID
INNER JOIN
tblJobTypes jt
ON jt.JobTypeID = J.JobTypeID
INNER JOIN
tblDepartments d
ON d.DepartmentID = J.DepartmentId
WHERE J.Closed = 0
AND J.Invoiced = 0
AND J.Active = 1
AND J.DepartmentId <> 2
AND J.JobID IN
(
SELECT JobID
FROM tblLoadDetails
)
AND J.JobID NOT IN
(
SELECT JobID
FROM tblLoadDetails
WHERE Delivered <> 1
)
Create a composite index on these fields:
tblJobs (Closed, Invoiced, Active) INCLUDE (DepartmentID)
If your tblLoadDetails.Delivered is a bit field, then create the following index:
tblLoadDetail (JobID, Delivered)
and rewrite the last condition as this:
SELECT *
FROM tblJobs j
INNER JOIN
tblCustomers c
ON c.CustomerID = J.CustomerID
INNER JOIN
tblJobTypes jt
ON jt.JobTypeID = J.JobTypeID
INNER JOIN
tblDepartments d
ON d.DepartmentID = J.DepartmentId
WHERE J.Closed = 0
AND J.Invoiced = 0
AND J.Active = 1
AND J.DepartmentId <> 2
AND
(
SELECT TOP 1 Delivered
FROM tblLoadDetails ld
WHERE ld.JobID = j.JobID
ORDER BY
Delivered
) = 1
I'm working this from the top of my head, so I haven't tried this out. But I think you could do this to remove the function. Replace the call to the function with these two clauses. This is assuming that 'Delivered' is a BIT field:
AND EXISTS (SELECT 1 FROM tblLoadDetails WHERE JobID = J.JobID)
AND NOT EXISTS (SELECT 1 FROM tblLoadDetails WHERE JobID = J.JobID AND Delivered = 0)
The AND EXISTS covers the UDF's #DetailCount > 0 check; the AND NOT EXISTS then covers the #DetailCount = #TrackingCount, the assumption I'm making is that you're looking to see if the job exists and everying to do with that job has been delivered. so if there's even one thing that hasn't been delivered, it needs to be excluded.
As mentioned: from top of head, and thus not tested or not profiled. I think I've got the logic right. If not, it should be a simple variation thereof.