SQL Multiple Left Joins performance is bad - sql

So, I have a rather simple query, which works, but very slow.
Is there a better way to optimize the query? Should I break out the LEFT JOINS on multiple columns? What about doing multiple runs and using Union ALL to join them together?
The tables have maybe 500,000 ROWS in them, and are indexed well.
Please help. Query takes forever to run
SELECT
ep.Id,
ep.DisplayName,
ep.EmailAddress,
COALESCE(
gs.DisplayNameMember + ' (' + gd.DisplayName + ')',
ea.DisplayName ,
ep.TrusteeUserAccountName,
ep.Trustee
) AS Trustee
FROM
dbo.ExchangePermissions ep WITH (NOLOCK)
LEFT JOIN dbo.GroupDetail gd WITH (NOLOCK) ON (ep.Trustee = gd.[Identity] OR ep.Trustee = gd.DisplayName OR ep.TrusteeUserAccountName = gd.SamAccountName)
LEFT JOIN dbo.GroupMemberShip gs WITH (NOLOCK) ON gd.name = gs.groupname
LEFT JOIN dbo.ExchangeAccount ea WITH (NOLOCK) ON (ep.Trustee = ea.[Identity] OR ep.Trustee = ea.DisplayName OR ep.TrusteeUserAccountName = ea.SamAccountName)
WHERE
ep.OTHERID= #MyParameter

The ORs in your LEFT JOINs are not helping performance at all. You should break them down into separate queries and UNION the results together. Working from Vykintas answer, we get the following:
SELECT
ep.Id,
ep.DisplayName,
ep.EmailAddress,
COALESCE(
gs.DisplayNameMember + ' (' + gd.DisplayName + ')',
ep.TrusteeUserAccountName,
ep.Trustee
) AS Trustee
FROM
dbo.ExchangePermissions ep WITH (NOLOCK)
LEFT JOIN dbo.GroupDetail gd WITH (NOLOCK) ON ep.Trustee = gd.[Identity]
LEFT JOIN dbo.GroupMemberShip gs WITH (NOLOCK) ON gd.name = gs.groupname
WHERE
ep.OTHERID= #MyParameter
UNION
SELECT
ep.Id,
ep.DisplayName,
ep.EmailAddress,
COALESCE(
gs.DisplayNameMember + ' (' + gd.DisplayName + ')',
ep.TrusteeUserAccountName,
ep.Trustee
) AS Trustee
FROM
dbo.ExchangePermissions ep WITH (NOLOCK)
LEFT JOIN dbo.GroupDetail gd WITH (NOLOCK) ON ep.Trustee = gd.DisplayName
LEFT JOIN dbo.GroupMemberShip gs WITH (NOLOCK) ON gd.name = gs.groupname
WHERE
ep.OTHERID= #MyParameter
UNION
SELECT
ep.Id,
ep.DisplayName,
ep.EmailAddress,
COALESCE(
gs.DisplayNameMember + ' (' + gd.DisplayName + ')',
ep.TrusteeUserAccountName,
ep.Trustee
) AS Trustee
FROM
dbo.ExchangePermissions ep WITH (NOLOCK)
LEFT JOIN dbo.GroupDetail gd WITH (NOLOCK) ON ep.TrusteeUserAccountName = gd.SamAccountName
LEFT JOIN dbo.GroupMemberShip gs WITH (NOLOCK) ON gd.name = gs.groupname
WHERE
ep.OTHERID= #MyParameter

Related

Stored procedure for a select statement

I got a select statement. I want to add a join to this select statement and the join which I want to add is at the bottom of this code. why am I unable to add one more left outer join for this select statement? The join which I want to add is at the bottom. I also need to write a stored procedure for the entire select statement:
SELECT
FactId, UserType,
wr.WorkRequestId, wr.XerisUserKey,
xu.CsuserUserID UserId,
u.fname UserFName, u.lname UserLName,
b.PatientId, p.firstname PatFName, p.lastname PatLName,
GroupId, HospiceGroupKey GroupKey, WR.ContactKey,
C.ContactId, C.FirstName, C.LastName,
Convert(datetime, (Convert(varchar, SD.Date, 101) + ' ' + ST.TimeOfDay )) Start_dtm,
Convert(datetime, (Convert(varchar, CD.Date, 101) + ' ' + CT.TimeOfDay )) End_dtm,
DATEDIFF(s,Convert(datetime,(Convert(varchar, SD.Date, 101) + ' ' + ST.TimeOfDay)),
Convert(datetime, (Convert(varchar, CD.Date, 101) + ' ' + CT.TimeOfDay ))) WRDuration,
(Convert(Decimal(18, 3), DATEDIFF(s, Convert(datetime,(Convert(varchar, SD.Date, 101) + ' ' + ST.TimeOfDay )),
Convert(datetime, (Convert(varchar, CD.Date, 101) + ' ' + CT.TimeOfDay ))))) *
(Convert(Decimal(18,3),LineItemCount)/Convert(Decimal(18,3),PatientBucketItemCount)) Duration,
CallBackNumber, WorkRequestType,
B.LineItemCount, ArchiveLocation, Processed,
ArchiveQueueType, TQA, Exclude, CallId
FROM
bi.dbo.FactWorkRequestTouches (NOlock) WR
INNER JOIN
bi.dbo.BridgePatientWorkRequest B ON B.WorkRequestId = WR.WorkRequestId
INNER JOIN
bi.dbo.dimPatient (NOlock) P ON B.PatientId = P.CphPatientID
INNER JOIN
bi.dbo.DimXerisUsers (NOlock) XU ON WR.XerisUserKey = XU.XerisUserKey
INNER JOIN
cdc.dbo.csuser (NOlock) U ON XU.CsuserUserID = u.user_id
INNER JOIN
bi.dbo.DimTimeOfDay (NOlock) ST ON WR.StartTimeOfDayKey = ST.TimeKey
INNER JOIN
bi.dbo.DimTimeOfDay (NOlock) CT ON WR.CompletedTimeOfDayKey = CT.TimeKey
INNER JOIN
bi.dbo.DimDate (NOlock) SD ON WR.StartDateKey = SD.DateKey
INNER JOIN
bi.dbo.DimDate (NOlock) CD ON WR.CompletedDateKey = CD.DateKey
LEFT OUTER JOIN
bi.dbo.DimContact (Nolock) C ON WR.ContactKey = C.ContactKey
WHERE
CompletedDateKey = '20140131'
AND ArchiveQueueType = 0
AND PatientBucketItemCount <> 0
AND Exclude = 0
AND P.ENDDate is Null
This is the join I want to add to this select statement
left outer join
ssdba.excelleRx_WebFOCUS.dbo.DimHospiceHiearchy (nolock) h on b.groupid = h.group_id
You are not allowed to call a table valued function remotely (ie across servers).
There is a workaround here:
Workaround for calling table-valued function remotely in SQL Server has even more issues
And more info here:
http://social.msdn.microsoft.com/Forums/en-US/1f0d2885-faa2-496a-b010-edc441260138/remote-tablevalued-function-calls-are-not-allowed?forum=transactsql

Conversion failed when converting date and/or time from character string. when using union all in sql server

I have this script for having totals on the left side and bottom part of my pivoted table,
I've got this error of 'Conversion failed when converting date and/or time from character string'. on line 19, but the line of code there is nothing to do with conversion.
the individual select works fine, but if they will be UNION they got this error.
DECLARE #sizenameS NVARCHAR (MAX)
SELECT #sizenameS = COALESCE(#sizenameS + ', ','') + QUOTENAME(SizeName)
FROM
( select DISTINCT SIZESET.SizeSetID, SizeName
from SIZESET
left join SHIPMENTSIZESET ON SIZESET.SizeSetID = SHIPMENTSIZESET.SizeSetID
left join SHIPMENTSCHED on SHIPMENTSCHED.ShipmentSchedID = SHIPMENTSIZESET.ShipmentSchedID
left join DESIGN on DESIGN.DesignID = SIZESET.DesignID
left join ARTICLE on ARTICLE.DesignID = DESIGN.DesignID where ArticleNo = 'EZT02'
)src2
ORDER BY SizeSetID
DECLARE #DownDownDown NVARCHAR (MAX)
SELECT #DownDownDown = COALESCE(#DownDownDown + 'ISNULL([' + CAST (SizeName AS VARCHAR) +'],0) + ', 'ISNULL([' + CAST(SizeName AS VARCHAR)+ '],0) + ')
FROM
( select DISTINCT SIZESET.SizeSetID, SizeName
from SIZESET
left join SHIPMENTSIZESET ON SIZESET.SizeSetID = SHIPMENTSIZESET.SizeSetID
left join SHIPMENTSCHED on SHIPMENTSCHED.ShipmentSchedID = SHIPMENTSIZESET.ShipmentSchedID
left join DESIGN on DESIGN.DesignID = SIZESET.DesignID
left join ARTICLE on ARTICLE.DesignID = DESIGN.DesignID where ArticleNo = 'EZT02'
)src3
ORDER BY SizeSetID
SET #DownDownDown = LEFT (#DownDownDown, LEN (#DownDownDown)-1)
DECLARE #ToTheLeft NVARCHAR(MAX)
SELECT #ToTheLeft = COALESCE(#ToTheLeft + ',ISNULL(SUM([' + CAST(SizeName AS VARCHAR)+']),0)', 'ISNULL(SUM([' + CAST(SizeName AS VARCHAR)+']),0)')
FROM
( select DISTINCT SIZESET.SizeSetID, SizeName
from SIZESET
left join SHIPMENTSIZESET ON SIZESET.SizeSetID = SHIPMENTSIZESET.SizeSetID
left join SHIPMENTSCHED on SHIPMENTSCHED.ShipmentSchedID = SHIPMENTSIZESET.ShipmentSchedID
left join DESIGN on DESIGN.DesignID = SIZESET.DesignID
left join ARTICLE on ARTICLE.DesignID = DESIGN.DesignID where ArticleNo = 'EZT02'
)src
ORDER BY SizeSetID
DECLARE #JerryPogi NVARCHAR (MAX)
SET #JerryPogi = 'SELECT *, ('+ #DownDownDown + ') AS [Grand Total] INTO #Pansamantala
FROM
(
select DISTINCT StartDate, EndDate, SizeName, Quantity
from SIZESET
left join SHIPMENTSIZESET ON SIZESET.SizeSetID = SHIPMENTSIZESET.SizeSetID
left join SHIPMENTSCHED on SHIPMENTSCHED.ShipmentSchedID = SHIPMENTSIZESET.ShipmentSchedID
left join DESIGN on DESIGN.DesignID = SIZESET.DesignID
left join ARTICLE on ARTICLE.DesignID = DESIGN.DesignID where ArticleNo = ''EZT02''
) JerryGwapo
PIVOT
(
SUM(Quantity)
FOR SizeName
IN('+#sizenameS +')
) JerryHot
ORDER BY StartDate
SELECT * FROM #Pansamantala
UNION ALL
SELECT '''',''Grand Total'','+#ToTheLeft +', isnull(SUM([Grand Total]),0) FROM #Pansamantala
DROP TABLE #Pansamantala'
exec(#JerryPogi)
The second column of #Pansamantala is EndDate, which I presume is a date type. In your UNION ALL, you're placing the string 'Grand Total' into the second column, which is not a valid date/time string.
To resolve this, either remove 'Grand Total' in the second half of your UNION ALL:
SELECT '''','''','+#ToTheLeft +', isnull(SUM([Grand Total]),0)
FROM #Pansamantala
or CAST the date columns in the first half of your UNION ALL to strings:
SELECT CAST(StartDate as varchar), CAST(EndDate as varchar), SizeName, Quantity
FROM #Pansamantala

Stored procedure sql server 2008 NOT IN

I have created a query which allows me to view all of the items that have been ordered by customers where the company name = Best Baths using the following code.
Select co.OrderID, cu.FName + ' ' + cu.SName as 'Name',
cu.Address1 + ', ' + cu.Address2 + ', ' + cu.Address3 as 'Dispatch Address',
cu.PostCode,
ma.MaterialName as 'Item',
mi.Price as 'Item Price',
co.DateOrdered as 'Order Date',
pm.DateReceived,
CASE WHEN la.Status = 'Blocked' THEN 'Blocked' ELSE 'Active' END AS Status
from Customers cu
-- inner join the following to find customers orders and cost
inner join CustomerOrder co on co.CustomerID = cu.CustomerID
inner join ItemOrder io on co.ID = io.ItemOrderID
inner join materialItem mi on io.MaterialID = mi.MaterialItemID
inner join Material ma on io.MaterialID = ma.MaterialItemID
left join ItemForInvoice ifi on io.ItemOrderID = ifi.ItemOrderID
left join Invoice iv on ifi.InvoiceItemID = iv.InvoiceItemID
left join PaymentMethod pm on iv.InvoiceID = pm.InvoiceID
left join LockedAccount la on pm.PaymentID = la.PaymentID
inner join Suppliers su on mi.SupplierID = su.SuppliersID
inner join SupplierDetails sd on su.SuppliersID = sd.SuppliersID
Where su.SuppliersName = 'Best Baths'
I now want to create a query thats shows items that have not yet been ordered, can anybody point me in the right direction?
It's not obvious from your query as to what tables what, but the basic query would be something like
SELECT items.id, COUNT(orders.itemid) AS cnt
FROM items
LEFT JOIN orders ON items.id = orders.itemid
GROUP BY items.id
HAVING (cnt = 0)
Annoscia, look this example:
(SELECT coll FROM TableA)
EXCEPT
(SELECT coll FROM TableB)
it's mean:
SELECT DISTINCT coll
FROM TableA
WHERE NOT EXISTS (SELECT *
FROM TableB
WHERE TableA.col1 = TableB.col1)
for your case it will be so:
Select co.OrderID, cu.FName + ' ' + cu.SName as 'Name',
cu.Address1 + ', ' + cu.Address2 + ', ' + cu.Address3 as 'Dispatch Address',
cu.PostCode,
ma.MaterialName as 'Item',
mi.Price as 'Item Price',
co.DateOrdered as 'Order Date',
pm.DateReceived,
CASE WHEN la.Status = 'Blocked' THEN 'Blocked' ELSE 'Active' END AS Status
from Customers cu
-- inner join the following to find customers orders and cost
inner join CustomerOrder co on co.CustomerID = cu.CustomerID
inner join ItemOrder io on co.ID = io.ItemOrderID
inner join materialItem mi on io.MaterialID = mi.MaterialItemID
inner join Material ma on io.MaterialID = ma.MaterialItemID
left join ItemForInvoice ifi on io.ItemOrderID = ifi.ItemOrderID
left join Invoice iv on ifi.InvoiceItemID = iv.InvoiceItemID
left join PaymentMethod pm on iv.InvoiceID = pm.InvoiceID
left join LockedAccount la on pm.PaymentID = la.PaymentID
inner join Suppliers su on mi.SupplierID = su.SuppliersID
inner join SupplierDetails sd on su.SuppliersID = sd.SuppliersID
EXCEPT
Select co.OrderID, cu.FName + ' ' + cu.SName as 'Name',
cu.Address1 + ', ' + cu.Address2 + ', ' + cu.Address3 as 'Dispatch Address',
cu.PostCode,
ma.MaterialName as 'Item',
mi.Price as 'Item Price',
co.DateOrdered as 'Order Date',
pm.DateReceived,
CASE WHEN la.Status = 'Blocked' THEN 'Blocked' ELSE 'Active' END AS Status
from Customers cu
-- inner join the following to find customers orders and cost
inner join CustomerOrder co on co.CustomerID = cu.CustomerID
inner join ItemOrder io on co.ID = io.ItemOrderID
inner join materialItem mi on io.MaterialID = mi.MaterialItemID
inner join Material ma on io.MaterialID = ma.MaterialItemID
left join ItemForInvoice ifi on io.ItemOrderID = ifi.ItemOrderID
left join Invoice iv on ifi.InvoiceItemID = iv.InvoiceItemID
left join PaymentMethod pm on iv.InvoiceID = pm.InvoiceID
left join LockedAccount la on pm.PaymentID = la.PaymentID
inner join Suppliers su on mi.SupplierID = su.SuppliersID
inner join SupplierDetails sd on su.SuppliersID = sd.SuppliersID
Where su.SuppliersName = 'Best Baths'
If you're after the materials (i.e. item) that have not yet been ordered, then an NOT EXISTS clause will work well. You only need to check that it has not been involved in an order via ItemOrder table.
Select ma.MaterialName as [Item],
mi.Price as [Item Price]
from Material ma
join materialItem mi on io.MaterialID = mi.MaterialItemID
where not exists (select *
from ItemOrder io
where io.MaterialID = ma.MaterialItemID)
PLEASE do not quote column aliases using (') single quotes in future, use the square brackets.

Error while using the Group By Clause

I am getting the sql server error "the text ntext and image data types cannot be compared or sorted except when using is null or like" while executing
SELECT r.Shift, l.lab_title AS [Assigned Lab], u.user_name AS [L/A],
CONVERT(varchar(100), t.Time) + ' To ' + CONVERT(varchar(100), h.Time) AS Timing
FROM table_roaster_time_table AS r
INNER JOIN table_time AS t ON r.timeId = t.timeId AND r.timeId = t.timeId
INNER JOIN table_user AS u ON r.user_id = u.user_id
INNER JOIN table_labs AS l ON r.lab_id = l.lab_id
INNER JOIN table_time2 AS h ON r.timeId2 = h.timeId2
GROUP BY r.Shift, l.lab_title, u.user_name
Don't know what's the problem. I have used aggregate function also with it, just for formality but it's not working.
I'm guessing your r.Shift column is a text or ntext type. Because of this it cannot be used in a group by
One option might be to use a CAST on the suspect column, but you might loose data. Example:
SELECT r.Shift, l.lab_title AS [Assigned Lab], u.user_name AS [L/A], CONVERT(varchar(100), t.Time) + ' To ' + CONVERT(varchar(100), h.Time) AS Timing
FROM table_roaster_time_table AS r INNER JOIN
table_time AS t ON r.timeId = t.timeId AND r.timeId = t.timeId INNER JOIN
table_user AS u ON r.user_id = u.user_id INNER JOIN
table_labs AS l ON r.lab_id = l.lab_id INNER JOIN
table_time2 AS h ON r.timeId2 = h.timeId2
GROUP BY CAST(r.Shift as varchar(max), l.lab_title, u.user_name
You could also look at querying the data without the text column and then doing a second query to get the missing column. Example:
with temp as
(
SELECT l.lab_title AS [Assigned Lab], u.user_name AS [L/A], CONVERT(varchar(100), t.Time) + ' To ' + CONVERT(varchar(100), h.Time) AS Timing
FROM table_roaster_time_table AS r INNER JOIN
table_time AS t ON r.timeId = t.timeId AND r.timeId = t.timeId INNER JOIN
table_user AS u ON r.user_id = u.user_id INNER JOIN
table_labs AS l ON r.lab_id = l.lab_id INNER JOIN
table_time2 AS h ON r.timeId2 = h.timeId2
GROUP BY l.lab_title, u.user_name
)
SELECT r.Shift, t.lab_title AS [Assigned Lab], t.user_name AS [L/A] --etc
FROM table_roaster_time_table AS r
INNER JOIN temp as t
on r.id = t.id --or whatver
Also, this SQL seems unnecessary:
r.timeId = t.timeId AND r.timeId = t.timeId

SQL Error 1016 - Inner Joins

I'm trying to add inner joins to old SQL code to make it run more efficiently. But when I added them and tried to execute I get this error:
1016, Line 12 Outer join operators cannot be specified in a query containing joined tables
Here's the query:
select a.s_purchase_order as order_id,
a.order_type,
a.nobackorder,
a.order_note,
a.note,
a.rqst_dlvry_date,
b.customer_name ,
c.store_name,
(c.store_name + ',' + isnull(c.address1 + ',', ' ') + isnull(c.city + ',', ' ') + isnull(c.state_cd+ ',', ' ') + isnull( c.zipcode, ' ')) as store_info,
d.supplier_account
from VW_CustomerOrder a, Customer b, Store c, eligible_supplier d
where a.customer = c.customer
and a.store = c.store
and a.customer = b.customer
and c.customer *= d.customer
and c.store *= d.store
and a.supplier *= d.supplier
and a.purchase_order = #order_id
and a.customer = #customer_id
and a.store=#store_id
and a.supplier = #supplier_id
Any idea what's causing it? I'm guessing it has something to do with the isnull?
Did you try this? It replaces your commas between your tables with INNER JOIN and LEFT JOIN
select a.s_purchase_order as order_id,
a.order_type,
a.nobackorder,
a.order_note,
a.note,
a.rqst_dlvry_date,
b.customer_name ,
c.store_name,
(c.store_name + ',' + isnull(c.address1 + ',', ' ') + isnull(c.city + ',', ' ') + isnull(c.state_cd+ ',', ' ') + isnull( c.zipcode, ' ')) as store_info,
d.supplier_account
from VW_CustomerOrder a
INNER JOIN Customer b
ON a.customer = b.customer
INNER JOIN Store c
ON a.customer = c.customer
and a.store = c.store
LEFT JOIN eligible_supplier d
ON c.customer = d.customer
and c.store = d.store
and a.supplier = d.supplier
where a.purchase_order = #order_id
and a.customer = #customer_id
and a.store=#store_id
and a.supplier = #supplier_id
If you left your "*=" join operators in the code after you converted it to ANSI syntax, that would explain your error. Use = for all equality tests when using ANSI syntax -- the type of your JOIN should be explicit in the JOIN declaration itself (INNER, LEFT, RIGHT, etc.)