Query takes forever to output info - tips on optimization - sql

I have a query that works awesomely - but - it takes about 10 minutes to load up. Which is insane. And I would like for it to run faster than it currently does now.
I was wondering if there were any tips I could take to optimize my query to make it run faster?
select DISTINCT
c.PaperID,
cdd.CodesF,
c.PageCount,
prr.projectname,
u.firstname + ' ' + u.lastname as Name,
ett.EventName,
cast(c.AssignedDate as DATE) [AssignedDate],
cast(ev.EventCompletionDate as DATE) [CompletionDate],
ar.ResultDescription,
a.Editor
from tbl_Papers c
left outer join (select cd.PaperId, count(*) as CodesF
from tbl_PaperCodes cd group by cd.PaperId) cdd
on cdd.PaperId = c.PaperId
left outer join
(SELECT
wfce.PaperEventActionNum,
c.PaperId,
CONVERT(varchar,wfce.ActionDate,101) CompletionDate,
pr.ProjectName,
wfce.ActionUserId,
u.firstname+' '+u.lastname [Editor]
FROM
dbo.tbl_WFPaperEventActions wfce
INNER JOIN dbo.tbl_Papers c ON wfce.PaperId = c.PaperId
INNER JOIN tbl_Providers p ON p.ProviderID = c.ProviderID
INNER JOIN tbl_Sites s ON s.SiteID = p.SiteID
INNER JOIN tbl_Projects pr ON s.ProjectId=pr.ProjectId
INNER JOIN tbl_Users u ON wfce.ActionUserId=u.UserId
WHERE
wfce.EventId = 204
AND c.Papersource =0
GROUP BY
wfce.PaperEventActionNum,
c.PaperId,
CONVERT(varchar,wfce.ActionDate,101),
pr.ProjectName,
wfce.ActionUserId,
u.firstname+' '+u.lastname
)a ON a.PaperId=c.PaperId,
tbl_Providers p, tbl_Sites s,
tbl_Projects prr, tbl_WFPaperEvents ev,
tbl_Users u, tbl_WFPaperEventTypes ett,
tbl_WFPaperEventActions arr, tbl_WFPaperEventActionResults ar
where s.SiteId = p.SiteId
and p.ProviderId = c.ProviderId
and s.ProjectId = prr.ProjectId
and ev.PaperId = c.PaperId
and ev.EventCreateUserId = u.UserId
and ev.EventCompletionDate >= dateadd(day,datediff(day,1,GETDATE()),0)
and ev.EventCompletionDate < dateadd(day,datediff(day,0,GETDATE()),0)
and ev.EventStatusId = 3
and ev.EventId in (201, 203)
and c.Papersource =0--Offshore
and ev.EventId=ett.EventID
and arr.PaperId=c.PaperId
and arr.EventId=ev.EventId
and arr.EventId=ar.EventID
and arr.ActionResultId=ar.ResultID
and arr.ActionResultId in (1,2,3,4)
order by paperid, u.FirstName + ' ' + u.LastName

You need to re-look carefully at every piece of this query and ask yourself, is that needed?
Take the subquery with alias a.
It joins 6 tables, but if you trace up to your final select clause only [Editor] is supplied from that alias. So do you need 6 tables to arrive at editor? No you don't in fact you only need 2 tbl_WFPaperEventActions and tbl_Users. Furthermore, this subquery is grouping by 6 items including a date, but 3 of those items are not used anywhere else in the overall query - so why go include these in the grouping? This allows us to drop 3 of the joined tables.
Of the remaining 3 grouping items a further 1 can be substituted to avoid the join between tbl_WFPaperEventActions and tbl_Papers because the join condition is "wfce.PaperId = c.PaperId", all we need then is to group by wfce.PaperId instead of c.PaperId
Finally we are then interested in the field wfce.PaperEventActionNum this is supplied by the subquery but isn't used in the larger query? Why provide that field is it isn't used? Well it turns out that it should be used to complete a join. The subquery aliased as a needs joining into the outer query on both PaperEventActionNum and PaperId. This by the way also requires that the whole subquery needs to be pushed down the joining structure to comply with ANSI join syntax rules.
Never "mix" ANSI join syntax with joins done "the old fashioned way"
This really is a recipe for a disaster.
Below I have "started" some amendments to your query, but I cannot really complete it as I have no way to test any part of it; and I don't know your data model at all.
Personally, I would re-start this query from scratch, starting lean and adding item by item to ensure it remains lean.
SELECT DISTINCT /* distinct isn't a good solution here */
c.PaperID
, cdd.CodesF
, c.PageCount
, prr.projectname
, u.firstname + ' ' + u.lastname AS Name
, ett.EventName
, CAST(c.AssignedDate AS date) [AssignedDate]
, CAST(ev.EventCompletionDate AS date) [CompletionDate]
, ar.ResultDescription
, a.Editor
FROM tbl_Papers c
LEFT OUTER JOIN ( -- can this be an inner join instead?
SELECT
cd.PaperId
, COUNT(*) AS CodesF
FROM tbl_PaperCodes cd
GROUP BY
cd.PaperId
) cdd
ON cdd.PaperId = c.PaperId
INNER JOIN tbl_Providers p ON c.ProviderId = p.ProviderId
INNER JOIN tbl_Sites s ON p.SiteId = s.SiteId
INNER JOIN tbl_Projects prr ON s.ProjectId = prr.ProjectId
INNER JOIN tbl_WFPaperEvents ev ON c.PaperId = ev.PaperId
INNER JOIN tbl_Users u ON ev.EventCreateUserId = u.UserId
INNER JOIN tbl_WFPaperEventTypes ett ON ev.EventId = ett.EventID
INNER JOIN tbl_WFPaperEventActions arr ON c.PaperId = arr.PaperId
AND ev.EventId = arr.EventId
INNER JOIN tbl_WFPaperEventActionResults ar ON arr.EventId = ar.EventID
AND arr.ActionResultId = ar.ResultID
AND arr.ActionResultId IN (1, 2, 3, 4)
LEFT OUTER JOIN (
SELECT
wfce.PaperEventActionNum
, wfce.PaperId
--, c.PaperId
--, CONVERT(varchar, wfce.ActionDate, 101) CompletionDate -- cast to date here
--, pr.ProjectName
--, wfce.ActionUserId
, u.firstname + ' ' + u.lastname [Editor]
FROM dbo.tbl_WFPaperEventActions wfce
--INNER JOIN dbo.tbl_Papers c ON wfce.PaperId = c.PaperId
--INNER JOIN tbl_Providers p ON p.ProviderID = c.ProviderID
--INNER JOIN tbl_Sites s ON s.SiteID = p.SiteID
--INNER JOIN tbl_Projects pr ON s.ProjectId = pr.ProjectId
tbl_Users INNER JOIN u ON wfce.ActionUserId = u.UserId
WHERE wfce.EventId = 204
AND c.Papersource = 0
GROUP BY
wfce.PaperEventActionNum
, wfce.PaperId
--, c.PaperId
--, CONVERT(varchar, wfce.ActionDate, 101)
--, pr.ProjectName
--, wfce.ActionUserId
, u.firstname + ' ' + u.lastname
) a
ON c.PaperId = a.PaperId AND arr.PaperEventActionNum = a.PaperEventActionNum
WHERE ev.EventCompletionDate >= DATEADD(DAY, DATEDIFF(DAY, 1, GETDATE()), 0)
AND ev.EventCompletionDate < DATEADD(DAY, DATEDIFF(DAY, 0, GETDATE()), 0)
AND ev.EventStatusId = 3
AND ev.EventId IN (201, 203)
AND c.Papersource = 0--Offshore
ORDER BY
paperid, u.FirstName + ' ' + u.LastName
I really do hate DISTINCT. It is nasty. It does not solve problems, it just hides them; AND slows down everything to do the hiding.
Use distinct in inverse proportion to query complexity:
if a query is really simple you can use distinct
If a query is complex do not use distinct

Check how many of fields on which you have join, where and group by clauses, have indexes. Every non-indexed field can negatively affect performance.
Calculated fields in GROUP BY are probably a pain, as well as DISTINCT (especially if they are not indexed). E.g. grouping on something like u.ID instead of u.firstname+' '+u.lastname or pr.ProjectId i/o pr.ProjectName should make things faster (you can sort the output according to the other criteria if needed).
Do you really need left join where you use it? I.e. do you want to keep the tables from the other side of the join even when there is no match on the other side? If not, replace it with inner join.
Various small improvements here, e.g.:
(assuming Papersource and EventId are indexes):
FROM
(SELECT * FROM dbo.tbl_WFPaperEventActions WHERE EventId = 204) wfce
INNER JOIN
(SELECT * FROM dbo.tbl_Papers WHERE Papersource = 0) c
ON wfce.PaperId = c.PaperId
INNER JOIN tbl_Providers p ON p.ProviderID = c.ProviderID
INNER JOIN tbl_Sites s ON s.SiteID = p.SiteID
INNER JOIN tbl_Projects pr ON s.ProjectId=pr.ProjectId
INNER JOIN tbl_Users u ON wfce.ActionUserId=u.UserId
instead of
FROM
dbo.tbl_WFPaperEventActions wfce
INNER JOIN dbo.tbl_Papers c ON wfce.PaperId = c.PaperId
INNER JOIN tbl_Providers p ON p.ProviderID = c.ProviderID
INNER JOIN tbl_Sites s ON s.SiteID = p.SiteID
INNER JOIN tbl_Projects pr ON s.ProjectId=pr.ProjectId
INNER JOIN tbl_Users u ON wfce.ActionUserId=u.UserId
WHERE
wfce.EventId = 204
AND c.Papersource =0
or (if I understood the idea correctly):
and ev.EventCompletionDate BETWEEN (
dateadd(day, -1, GETDATE()) and dateadd(ns, -1, GETDATE())
instead of:
and ev.EventCompletionDate >= dateadd(day,datediff(day,1,GETDATE()),0)
and ev.EventCompletionDate < dateadd(day,datediff(day,0,GETDATE()),0)
In general: ask yourself what exactly you want to achieve with this query, which parts of the data are relevant for it, how many of your source tables can be replaced with snippets from them (this can make JOINs work faster), and try to be consistent regarding the usage of JOIN and WHERE clauses.

Related

Optimizing Multiple SQL Queries

I have 2 queries that I want to optimize but I don't know how. The execution time is not acceptable for me.
I'm working with jira database and did query to show different tasks with some attributes.
The code is:
SET NOCOUNT ON
DROP TABLE IF EXISTS #TT
DROP TABLE IF EXISTS #TT1
DROP TABLE IF EXISTS #TT2
SELECT DISTINCT concat(pr.[pkey], '-', ji.[issuenum]) AS 'Ключ'
,concat('https://sd.finam.ru/browse/', pr.[pkey], '-', ji.[issuenum]) AS 'Ссылка'
,p.[pname] AS 'П'
,users.[display_name] AS 'Исполнитель'
,CAST(ji.[CREATED] AS smalldatetime) AS 'Создан'
,CAST(ji.[RESOLUTIONDATE] AS smalldatetime) AS 'Дата резолюции'
,ji.[issuenum]
INTO #TT
FROM
[jiraissue] AS ji
LEFT OUTER JOIN [changegroup] AS cg ON (cg.[issueid] = ji.[id])
LEFT OUTER JOIN [changeitem] AS ci ON (ci.[groupid] = cg.[id]) AND ci.FIELDTYPE='jira' AND ci.FIELD='status'
LEFT OUTER JOIN [app_user] AS au ON (au.[user_key] = cg.[AUTHOR])
LEFT OUTER JOIN [issuetype] AS itype ON (itype.[ID] = ji.[issuetype])
LEFT OUTER JOIN [priority] AS p ON (p.[ID] = ji.[PRIORITY])
LEFT OUTER JOIN [project] AS pr ON (pr.[ID] = ji.[PROJECT])
LEFT OUTER JOIN [cwd_user] as users ON (users.[user_name] = ji.[ASSIGNEE])
WHERE cg.[CREATED] >= CONVERT(datetime, '2021-12-01') AND cg.[CREATED] <= CONVERT(datetime, '2022-01-01') and CONVERT(NVARCHAR(MAX), ci.[NEWSTRING]) = N'Done'
AND itype.pname = 'Incident'
SELECT DISTINCT concat(pr.[pkey], '-', ji.[issuenum]) AS 'Ключ'
,system_t.[NAME] AS 'Контур ИС'
,system_t_t.[NAME] AS 'Критичность системы'
INTO #TT1
FROM
[jiraissue] AS ji
LEFT OUTER JOIN [changegroup] AS cg ON (cg.[issueid] = ji.[id])
LEFT OUTER JOIN [changeitem] AS ci ON (ci.[groupid] = cg.[id]) AND ci.FIELDTYPE='jira' AND ci.FIELD='status'
LEFT OUTER JOIN [app_user] AS au ON (au.[user_key] = cg.[AUTHOR])
LEFT OUTER JOIN [issuetype] AS itype ON (itype.[ID] = ji.[issuetype])
LEFT OUTER JOIN [project] AS pr ON (pr.[ID] = ji.[PROJECT])
LEFT OUTER JOIN [customfieldvalue] AS customfv ON (customfv.[ISSUE] = ji.[ID])
LEFT OUTER JOIN [AO_8542F1_IFJ_OBJ] AS system_t ON (system_t.[ID] = substring(customfv.[STRINGVALUE], PatIndex('%[0-9]%', customfv.[STRINGVALUE]), len(customfv.[STRINGVALUE])))
LEFT OUTER JOIN [AO_8542F1_IFJ_OBJ_ATTR] AS system_attr ON (system_t.[ID] = system_attr.[OBJECT_ID])
LEFT OUTER JOIN [AO_8542F1_IFJ_OBJ_ATTR_VAL] AS system_attr_val ON (system_attr.[ID] = system_attr_val.[OBJECT_ATTRIBUTE_ID])
LEFT OUTER JOIN [AO_8542F1_IFJ_OBJ] AS system_t_t ON (system_attr_val.[REFERENCED_OBJECT_ID] = system_t_t.[ID])
WHERE cg.[CREATED] >= CONVERT(datetime, '2021-12-01') AND cg.[CREATED] <= CONVERT(datetime, '2022-01-01') and CONVERT(NVARCHAR(MAX), ci.[NEWSTRING]) = N'Done'
AND (customfv.[CUSTOMFIELD] = 21003 OR customfv.[CUSTOMFIELD] = 21005)
AND (system_t.[OBJECT_TYPE_ID] = 136 OR system_t.[OBJECT_TYPE_ID] = 303 OR system_t.[OBJECT_TYPE_ID] = 143)
AND system_attr.[OBJECT_TYPE_ATTRIBUTE_ID] = 461
AND itype.pname = 'Incident'
SELECT ji.[issuenum]
,pr_pr.[pname] AS '(project) Project'
INTO #TT2
FROM
[jiraissue] AS ji
LEFT OUTER JOIN [customfieldvalue] AS customfv ON (customfv.[ISSUE] = ji.[ID])
LEFT OUTER JOIN [project] AS pr_pr ON (pr_pr.[ID] = CAST(customfv.[NUMBERVALUE] AS BIGINT))
LEFT OUTER JOIN [changegroup] AS cg ON (cg.[issueid] = ji.[id])
LEFT OUTER JOIN [changeitem] AS ci ON (ci.[groupid] = cg.[id]) AND ci.FIELDTYPE='jira' AND ci.FIELD='status'
LEFT OUTER JOIN [app_user] AS au ON (au.[user_key] = cg.[AUTHOR])
LEFT OUTER JOIN [issuetype] AS itype ON (itype.[ID] = ji.[issuetype])
WHERE cg.[CREATED] >= CONVERT(datetime, '2021-12-01') AND cg.[CREATED] <= CONVERT(datetime, '2022-01-01') and CONVERT(NVARCHAR(MAX), ci.[NEWSTRING]) = N'Done'
AND pr_pr.[pname] is not NULL
SELECT CTE.[Ключ], CTE.[Ссылка], CTE.[П], CTE.[Исполнитель], CTE.[Создан], CTE.[Дата резолюции], CTE2.[(project) Project], CTE1.[Контур ИС], CTE1.[Критичность системы], CTE.[issuenum]
FROM #TT CTE
LEFT OUTER JOIN #TT1 CTE1 ON (CTE1.[Ключ] = CTE.[Ключ])
LEFT OUTER JOIN #TT2 CTE2 ON (CTE2.[issuenum] = CTE.[issuenum])
DROP TABLE IF EXISTS #TT
DROP TABLE IF EXISTS #TT1
DROP TABLE IF EXISTS #TT2
There will be some information for the month before last.
summary of query
The next query is:
WITH CTE AS (
SELECT concat(p.pkey,'-',i.issuenum) AS 'Ключ',
cf.cfname,
cv.textvalue,
ROW_NUMBER() OVER (PARTITION BY i.issuenum ORDER BY i.issuenum) AS RowNumber_SLA
FROM customfield cf,
customfieldvalue cv,
jiraissue i,
project p
WHERE i.project = p.id
AND cv.issue = i.id
AND cv.customfield = cf.id
AND cf.customfieldtypekey = 'com.atlassian.servicedesk:sd-sla-field'
and i.issuenum IN ()
and CHARINDEX('"succeeded":false', TEXTVALUE) >0
)
SELECT CTE.Ключ
FROM CTE
WHERE RowNumber_SLA = 1
The goal is to get tasks where SLA has been failed.
So in and i.issuenum IN () my Python script is putting issue numbers that I got through previous query.
The average execution time is 3 minutes.
So, I want optimize this too, maybe join first query.
Sorry for my English. I'm not an English-speaking person.
P. S. Changing CONVERT(NVARCHAR(MAX), ci.[NEWSTRING]) = N'Done' to ci.[NEWSTRING] = 'Done' causing the error The data types ntext and varchar are incompatible in the equal to operator. Workaround - ci.[NEWSTRING] LIKE 'Done' fixing this.
The first query must be rewrite as :
SELECT DISTINCT
concat(pr.[pkey], '-', ji.[issuenum]) AS 'Ключ',
concat('https://sd.finam.ru/browse/', pr.[pkey], '-', ji.[issuenum]) AS 'Ссылка',
p.[pname] AS 'П',
users.[display_name] AS 'Исполнитель',
CAST(ji.[CREATED] AS SMALLDATETIME) AS 'Создан',
CAST(ji.[RESOLUTIONDATE] AS SMALLDATETIME) AS 'Дата резолюции',
ji.[issuenum]
INTO #TT
FROM [jiraissue] AS ji
INNER JOIN [changegroup] AS cg ON(cg.[issueid] = ji.[id])
INNER JOIN [changeitem] AS ci ON(ci.[groupid] = cg.[id])
AND ci.FIELDTYPE = 'jira'
AND ci.FIELD = 'status'
LEFT OUTER JOIN [app_user] AS au ON(au.[user_key] = cg.[AUTHOR])
INNER JOIN [issuetype] AS itype ON(itype.[ID] = ji.[issuetype])
LEFT OUTER JOIN [priority] AS p ON(p.[ID] = ji.[PRIORITY])
LEFT OUTER JOIN [project] AS pr ON(pr.[ID] = ji.[PROJECT])
LEFT OUTER JOIN [cwd_user] AS users ON(users.[user_name] = ji.[ASSIGNEE])
WHERE cg.[CREATED] >= CONVERT(DATETIME, '2021-12-01')
AND cg.[CREATED] <= CONVERT(DATETIME, '2022-01-01')
AND ci.[NEWSTRING] = 'Done'
AND itype.pname = 'Incident';
False outer joins are converted in INNER and I have aslo eliminate the ugly CONVERT to NVARCHAR(max)
Same troubles appears in the second query...

Return rows where a customer bought things on same day

Can someone help me with the rest of my Query.
This query gives me Customer, AdressNr, Date, Employee, Article, ActivityNr
from all the sales in my Company.
SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS Date,
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM
My goal is to filter this so i get only rows back where the customer has bought more then 1 Thing on the same day. It doesn't matter if a customer bought the same Article twice on the same day. I want too see this also.
It's to complicated to write some SQL Fiddle for you but in this Picture you can see what my goal is. I want to take away all rows with an X on the left side and thoose with a Circle i want to Keep.
As I don't speak German, I won't target this specifically to your SQL. But see the following quasi-code for a similar example that you should be able to apply to your own script.
SELECT C.CustomerName, O.OrderDate, O.OrderNumber
FROM CUSTOMER C
JOIN ORDERS O ON O.Customer_ID = C.Customer_ID
JOIN
(SELECT Customer_ID, OrderDate
FROM ORDERS
GROUP BY Customer_ID, OrderDate
HAVING COUNT(*) > 1) SRC
ON SRC.Customer_ID = O.Customer_ID AND SRC.OrderDate = O.OrderDate
In the script above, the last query (a subquery) would only return results where a customer had more than one order in a given day. By joining that to your main query, you would effectively produce the result asked in the OP.
Edit 1:
Regarding your comment below, I really recommend just going over your datamodel, trying to understand what's happening here, and fixing it on your own. But there is an easy - albeit hardly optimal solution to this by just using your own script above. Note, while this is not disastrous performance-wise, it's obviously not the cleanest, most effective method either. But it should work:
;WITH CTE AS (SELECT ad.Name + ' ' + ad.Vorname AS Customer,
pa.Kunde AS CustomerNr,
CONVERT(VARCHAR(10),p.datum,126) AS [Date],
(SELECT a.name + ' ' + a.Vorname AS Name FROM PRO_Mitarbeiter m LEFT JOIN ADR_Adressen a ON a.AdressNrADR=m.AdressNrADR WHERE m.MitNrPRO = l.MitNrPRO) as Employee,
p.Artikel_1 AS Article,
l.AufgabenNrCRM AS OrderNr
FROM ZUS_Therapie_Positionen p
INNER JOIN CRM_AufgabenLink l ON l.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN CRM_Aufgaben ab ON ab.AufgabenNrCRM = p.Id_Aktivitaet
INNER JOIN PRO_Auftraege pa ON pa.AuftragNrPRO = ab.AuftragNrPRO
INNER JOIN ADR_Adressen ad ON ad.AdressNrADR = pa.Kunde
INNER JOIN ADR_GruppenLink gl ON gl.AdressNrADR = ad.AdressNrADR
INNER JOIN ADR_Gruppen g ON g.GruppeADR = gl.GruppeADR
WHERE l.MitNrPRO != 0
GROUP BY l.AufgabenNrCRM,ad.Name,ad.Vorname,pa.Kunde,p.datum,p.Artikel_1,l.MitNrPRO
ORDER BY pa.Kunde,p.datum,l.AufgabenNrCRM)
SELECT C.*
FROM CTE C
JOIN (Select CustomerNr, [Date]
FROM CTE B
GROUP BY CustomerNr, [Date]
HAVING COUNT(*) > 1) SRC
ON SRC.CustomerNr = C.CustomerNr AND SRC.[Date] = C.[Date]
This should work directly. But as I said, this is an ugly workaround where we're basically all but fetching the whole set twice, as opposed to just limiting the sub query to just the bare minimum of necessary tables. Your choice. :)
Tried that also and it didnt work. I also made a new query trying to Keep it so simple as possible and it doesnt work either. It still give me Single values back..
SELECT p.Datum,a.AufgabenNrCRM,auf.Kunde FROM CRM_Aufgaben a
LEFT JOIN ZUS_Therapie_Positionen p ON p.Id_Aktivitaet = a.AufgabenNrCRM
LEFT JOIN PRO_Auftraege auf ON auf.AuftragNrPRO = a.AuftragNrPRO
LEFT JOIN
(SELECT pa.Datum,au.Kunde FROM CRM_Aufgaben aa
LEFT JOIN ZUS_Therapie_Positionen pa ON pa.Id_Aktivitaet = aa.AufgabenNrCRM
LEFT JOIN PRO_Auftraege au ON au.AuftragNrPRO = aa.AuftragNrPRO
GROUP BY pa.Datum,au.Kunde
HAVING COUNT(*) > 1) SRC
ON SRC.Kunde = auf.Kunde
WHERE p.datum IS NOT NULL
GROUP BY p.Datum,a.AufgabenNrCRM,auf.Kunde
ORDER BY auf.Kunde,p.Datum

MSSQL Query get latest value from two tables faster

This query pulls the timestamp (DT_CREATED) from two different tables and selecting the most recent timestamp. The INCIDENT_AUDIT_HISTORY table is quite large and even though I've improved performance by 10 seconds by adding indexes my query still takes over 20 seconds to run, which is longer than desired for the application. I'm wondering if there is a more efficient way to write this query?
SELECT i.NUMBER, i.PROBLEM, st.LABEL AS STATUS, i.ID_ASSIGNEE, r.LNAME + ', ' + r.FNAME AS ASIGNEE, c.LNAME + ', ' + c.FNAME AS CUST_NAME,
p.LABEL AS PRIORITY, i.DT_CREATED,
(SELECT MAX(DT_CREATED) AS LAST_WORK
FROM (SELECT TOP (1) DT_CREATED
FROM dbo.REP_WORK_HISTORY AS b
WHERE (i.NUMBER = INCIDENT_NUMBER) AND (ID_OWNER = r.ID)
ORDER BY DT_CREATED DESC
UNION
SELECT TOP (1) DT_CREATED
FROM dbo.INCIDENT_AUDIT_HISTORY AS c
WHERE (i.NUMBER = INCIDENT_NUMBER) AND (ID_OWNER = r.ID)
ORDER BY DT_CREATED DESC) AS a) AS LAST_HISTORY, g.GROUP_NAME FROM dbo.REPS AS r RIGHT OUTER JOIN
dbo.GROUPS AS g ON r.ID_DEFAULT_GROUP = g.ID RIGHT OUTER JOIN
dbo.INCIDENTS AS i ON r.ID = i.ID_ASSIGNEE LEFT OUTER JOIN
dbo.CUSTOMERS AS c ON i.ID_CUSTOMER = c.ID LEFT OUTER JOIN
dbo._PRIORITIES AS p ON i.PRIORITY = p.ID LEFT OUTER JOIN
dbo.INCIDENT_STATUSES AS st ON i.ID_STATUS = st.ID WHERE (st.TYPE <> 2) AND (st.TYPE <> 16)

My CASE statement is wrong. Any idea what I am doing wrong?

I am in a logjam.
When I run the following query, it works:
select DISTINCT l.Seating_Capacity - (select count(*)
from tblTrainings t1, tbllocations l
where l.locationId = t1.LocationId) as
availableSeats
from tblTrainings t1, tbllocations l
where l.locationId = t1.LocationId
However, we would like to add a CASE statement that says, when Seating_Capacity - total count as shown above = 0 then show 'FULL' message.
Otherwise, show remaining number.
Here is that query:
select DISTINCT case when l.Seating_Capacity - (select count(*)
from tblTrainings t1, tbllocations l
where l.locationId = t1.LocationId) = 0 then 'full' else STR(Seating_Capacity) end)
availableSeats
from tblTrainings t1, tbllocations l
where l.locationId = t1.LocationId
I am getting 'Incorrect syntax near ')' which is near 'End'
I am also getting an error that the inner Seating_Capacity is invalid column name.
Your assistance is greatly appreciated.
I must have been in a dream land because I thought it was working during testing.
Now, the app is live and it isn't working.
Thanks a lot in advance
select DISTINCT l.LocationId,c.courseId, c.coursename, l.Seating_Capacity - (select count(*)
from tblTrainings t1
where l.locationId = t1.LocationId and c.courseId = t1.courseId) as
availableSeats,d.dateid,d.trainingDates,d.trainingtime,c.CourseDescription,
i.instructorName,l.location,l.seating_capacity
from tblLocations l
Inner Join tblCourses c on l.locationId = c.locationId
left join tblTrainings t on l.locationId = t.LocationId and c.courseId = t.courseId
Inner Join tblTrainingDates d on c.dateid=d.dateid
Inner Join tblCourseInstructor ic on c.courseId = ic.CourseId
Inner Join tblInstructors i on ic.instructorId = i.instructorId
WHERE CONVERT(VARCHAR(10), d.trainingDates, 101) >= CONVERT(VARCHAR(10), GETDATE(), 101)
To avoid repeating the expression, you can use a WITH clause to simplify your query:
WITH (
-- Start with your query that already works
SELECT DISTINCT l.Seating_Capacity - (select count(*)
from tblTrainings t1, tbllocations l
where l.locationId = t1.LocationId) AS availableSeats
FROM tblTrainings t1, tbllocations l
WHERE l.locationId = t1.LocationId
) AS source
SELECT
-- Add a CASE statement on top of it
CASE WHEN availableSeats = 0 THEN 'Full'
ELSE STR(availableSeats)
END AS availableSeats
FROM source
You have an extra ) at the end of your case statement remove that.
0 then 'full' else STR(Seating_Capacity) end)
^^^
for Seating_Capacity try accessing it with table alias like l.Seating_Capacity
I think you are over complicating the query with your subquery. As I understand it then the following should work as you need:
SELECT AvailableSeats = CASE WHEN l.Seating_Capacity - COUNT(*) = 0 THEN 'Full'
ELSE STR(l.Seating_Capacity - COUNT(*))
END
FROM tblTrainings t1
INNER JOIN tblLocations l
ON l.LocationID = t1.LocationID
GROUP BY l.Seating_Capacity;
I have changed your else to STR(l.Seating_Capacity - COUNT(*)) because I assume you want to know the seats remaining, rather than just the capacity? If I have misinterpreted the requirement, just change it to STR(l.Seating_Capacity).
I have also switched your ANSI 89 implicit joins to ANSI 92 explicit joins, the standard changed over 20 years, and there are plenty of good reasons to switch to the newer syntax. But for completeness the ANSI 89 version of the above query would be:
SELECT AvailableSeats = CASE WHEN l.Seating_Capacity - COUNT(*) = 0 THEN 'Full'
ELSE STR(l.Seating_Capacity - COUNT(*))
END
FROM tblTrainings t1, tblLocations l
WHERE l.LocationID = t1.LocationID
GROUP BY l.Seating_Capacity;
EDIT
To adapt your full query you can simply replace your subquery in the select, with a joined subquery:
SELECT l.LocationId,
c.courseId,
c.coursename,
CASE WHEN l.Seating_Capacity - t.SeatsTaken = 0 THEN 'Full'
ELSE STR(l.Seating_Capacity - t.SeatsTaken)
END AS availableSeats,
d.dateid,
d.trainingDates,
d.trainingtime,
c.CourseDescription,
i.instructorName,
l.location,
l.seating_capacity
FROM tblLocations l
INNER JOIN tblCourses c
ON l.locationId = c.locationId
LEFT JOIN
( SELECT t.LocationID, t.CourseID, SeatsTaken = COUNT(*)
FROM tblTrainings t
GROUP BY t.LocationID, t.CourseID
) t
ON l.locationId = t.LocationId
AND c.courseId = t.courseId
INNER JOIN tblTrainingDates d
ON c.dateid=d.dateid
INNER JOIN tblCourseInstructor ic
ON c.courseId = ic.CourseId
INNER JOIN tblInstructors i
ON ic.instructorId = i.instructorId
WHERE d.trainingDates >= CAST(GETDATE() AS DATE);
JOINs tend to optimise better than correlated subqueries (although sometimes the optimiser can determine that a JOIN would work instead), it also means that you can reference the result (SeatsTaken) multiple times without re-evaluating the subquery.
In addition, by moving the count to a subquery, and removing the join to tblTrainings I think you eliminate the need for DISTINCT which should improve the performance.
Finally I have changed this line:
WHERE CONVERT(VARCHAR(10), d.trainingDates, 101) >= CONVERT(VARCHAR(10), GETDATE(), 101)
To
WHERE d.trainingDates >= CAST(GETDATE() AS DATE);
I don't know if you do, but if you had an index on d.TrainingDates then by converting it to varchar to compare it to today you remove the ability for the optimiser to use this index, since you are only saying >= midnight today, there is no need to perform any conversion on d.TrainingDates, and all you need to do is remove the time portion of GETDATE(), which can be done by casting to DATE. More on this is contained in this article (Yet another gem from Aaron Bertrand)

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