Looking for SQL count performance improvements. - sql

I'm refactoring some older SQL, which is struggling after 4 years and 1.7m rows of data. Is there a way to improve the following MS SQL Query:
SELECT ServiceGetDayRange_1.[Display Start Date],
SUM (CASE WHEN Calls.line_date BETWEEN [Start Date] AND [End Date] THEN 1 ELSE 0 END) AS PerDayCount
FROM dbo.ServiceGetDayRange(GETUTCDATE(), 30, #standardBias, #daylightBias, #DST_startMonth, #DST_endMonth, #DST_startWeek, #DST_endWeek, #DST_startHour, #DST_endHour, #DST_startDayNumber, #DST_endDayNumber) AS ServiceGetDayRange_1 CROSS JOIN
(select [line_date] from dbo.l_log where dbo.l_log.line_date > dateadd(day,-31,GETUTCDATE())) as Calls
GROUP BY ServiceGetDayRange_1.[Display Start Date], ServiceGetDayRange_1.[Display End Date]
ORDER BY [Display Start Date]
It counts log entries over the previous 30 days (ServiceGetDayRange function returns table detailing ranges, TZ aligned) for plotting on a chart.. useless information, but i'm not the client.
The execution plan states 99% of the exec time is used in counting the entries.. as you would expect. Very little overhead in working out the TZ offsets (remember max 30 rows).
Stupidly i thought 'ah, indexed view' but then realised i cant bind to a function.
Current exec time if 6.25 seconds. Any improvement on that +rep
Thanks in advance.

Is it faster if you turn the CASE into a WHERE?
SELECT ServiceGetDayRange_1.[Display Start Date], COUNT(*) AS PerDayCount
FROM dbo.ServiceGetDayRange(GETUTCDATE(), 30, #standardBias, #daylightBias, #DST_startMonth, #DST_endMonth, #DST_startWeek, #DST_endWeek, #DST_startHour, #DST_endHour, #DST_startDayNumber, #DST_endDayNumber) AS ServiceGetDayRange_1 CROSS JOIN
(select [line_date] from dbo.l_log where dbo.l_log.line_date > dateadd(day,-31,GETUTCDATE())) as Calls
WHERE Calls.line_date BETWEEN [Start Date] AND [End Date]
GROUP BY ServiceGetDayRange_1.[Display Start Date], ServiceGetDayRange_1.[Display End Date]
ORDER BY [Display Start Date]

6.25 seconds for nearly 2m rows is pretty good.. maybe try a count of valid rows (your 1/0 conditional should allow that) as opposed to a sum of values.. I think that's more efficient in oracle environments.

Related

How to group totals

I am trying to group by category - But the SQL I am using is grouping them all by date.
Example:
If a user selects a date range of 01/04/17 - 20/04/17 it will show them total number found under category A
Whats actually happening:
The results are showing Category A 10 times and showing me the total number of each date rather than a complete grouped total
Hope this makes sense
SELECT tbl_ComplaintsCoded.CauseManager, Count(tbl_ComplaintsCoded.CauseManager) AS CountOfCauseManager, tbl_ComplaintsCoded.[Account Number], tbl_ComplaintsCoded.TouchCSM, tbl_ComplaintsCoded.[Mail Date]
FROM tbl_ComplaintsCoded
GROUP BY tbl_ComplaintsCoded.CauseManager, tbl_ComplaintsCoded.[Account Number], tbl_ComplaintsCoded.TouchCSM, tbl_ComplaintsCoded.[Mail Date]
HAVING (((tbl_ComplaintsCoded.TouchCSM)=[Forms]![frm_Central_Reporting]![Combo209]) AND ((tbl_ComplaintsCoded.[Mail Date]) Between [Forms]![frm_Central_Reporting]![Text204] And [Forms]![frm_Central_Reporting]![Text206]));
this should get what you want:
SELECT tbl_ComplaintsCoded.CauseManager, Count(tbl_ComplaintsCoded.CauseManager) AS CountOfCauseManager, tbl_ComplaintsCoded.[Account Number], tbl_ComplaintsCoded.TouchCSM, tbl_ComplaintsCoded.[Mail Date]
FROM tbl_ComplaintsCoded
WHERE tbl_ComplaintsCoded.TouchCSM = [Forms]![frm_Central_Reporting]![Combo209]
AND (tbl_ComplaintsCoded.[Mail Date] BETWEEN [Forms]![frm_Central_Reporting]![Text204] AND [Forms]![frm_Central_Reporting]![Text206])
GROUP BY tbl_ComplaintsCoded.CauseManager
HAVING CountOfCauseManager > 0;
Also, please read: WHERE vs HAVING

Date Range in an Access Crosstab

Trying to get a Crosstab to bring up a prompt when a query is opened to allow a date range (start and end) to be input (dd-mm-yyyy) so that only this data comes back when the query is ran.
Currently sitting on the following code;
TRANSFORM Count(AlphaData.[Invoice]) AS CountOfInvoice
SELECT AlphaData.[Reason], Count(AlphaData.[Invoice]) AS [Total Of Invoice]
FROM AlphaData
WHERE ((AlphaData.[DateRaised]) Between AlphaData.[DateRaised] And AlphaData.[DateRaised])
GROUP BY AlphaData.[Reason]
PIVOT Format([DateRaised],"Short Date");
But cannot for the life of me get around the "MS Access DB engine does not recognise 'Alphadata.[DateRaised:]' as a valid field name or expression" issue.
The "WHERE" portion of the query does work in other queries, but it just goes to pot when it's applied in a crosstab.
Any suggestions?
It seems a bit mixed up. How about:
PARAMETERS
[From Date:] DateTime,
[To Date:] DateTime;
TRANSFORM
Count(*) AS CountOfInvoice
SELECT
AlphaData.[Reason],
Sum(AlphaData.[Invoice]) AS [Total Of Invoice]
FROM
AlphaData
WHERE
AlphaData.[DateRaised] Between [From Date:] And [To Date:]
GROUP BY
AlphaData.[Reason]
PIVOT
Format([DateRaised],"Short Date");
You need to add the parameters to the query:
PARAMETERS [Start Date] DateTime, [End Date] DateTime;
TRANSFORM Count(AlphaData.Invoice) AS CountOfInvoice
SELECT AlphaData.Reason, Count(AlphaData.Invoice) AS [Total Of Invoice]
FROM AlphaData
WHERE (((AlphaData.DateRaised) Between [Start Date] And [End Date]))
GROUP BY AlphaData.Reason
PIVOT Format([DateRaised],"Short Date");
(note: parameter added as the first line, and then used in the Between statement).
If you're using the graphical interface you need to look for the Parameter option:
and enter your parameters in the dialog box:
I didn't realise this would happen with a cross-tab as you can just type the parameter in for a select query:
SELECT Invoice, Reason, DateRaised
FROM AlphaData
WHERE DateRaised=[Start Date]

Getting null values when trying to join Two tables with Same Column Name

Need some help
I have two tables CallsData and Plananumbers
I need to join them based on three conditions, SiteID, Date, Time
When I use the conditions SiteID and Date it's fine but when I add Time to the join condition I am getting NULL values.
Have changed the data type of all the columns to be Varchar, still no GO.
Have tried using the case statement to make sure I have the same set of values on both the table for Time column, no GO.
Please help.
Below is the query
SELECT A.[Date]
,A.[Time]
,A.[SiteID]
,A.[Split Skill]
,P.[ForOff]
,P.[HandlePlan]
,A.[ACD Calls]
,A.[ACCEPTABLE]
,A.[ABN Calls]
,A.[ACD Time]
,A.[ACW Time]
,A.[Hold Time]
,A.[Ring Time]
,A.[ANSTIME]
,A.[ABNTIME]
,A.[Service Level%]
,A.[SL Threshold]
,A.[Trans Out]
,A.[RONA]
,A.[Avail Time]
,A.[Staff Time]
,A.[Max Delay]
,A.[Short ABN]
,A.[Applied ACD]
FROM
[Stageing].[dbo].[Ac05CallsSiteIdTemp] as A
Left Join
Stageing.dbo.FinalPlanNumbersDemo as P on A.[Time] = P.[Time]
Id hazard a guess that there are no exact times between the tables.
Either try using a range of times OR
If just date (and not time) is important perhaps use just this part of each date, consider using the Date type.
If it is date and time try and reduce the precision of the time element.

SQL Simple Group By causing duplicates sections

I have a SQL query that is causing me trouble. The SQL That I have so far is the following:
SELECT Dated, [Level 1 reason], SUM(Duration) AS Mins
FROM Downtime
GROUP BY Dated, [Level 1 reason]
Now the problem I am having is that the results include multiple reasons, rather than being grouped together as I require. An example of the problem results is the following:
1/2/2013 10:02:00 AM Westport 2
1/2/2013 10:17:00 AM Westport 9
1/2/2013 10:48:00 AM Engineering 5
1/2/2013 11:01:00 AM Facilities 6
The intended result is that there be a single Westport group for a date. The query also needs to handle multiple dates, but those weren't included in the snippet for readability.
Thanks for any help. I know it's some simple reason, but I can't figure it out.
**EDIT IN: sorry, I am performing this in Access.
Removing the Group by Dated results in an error in Access. I am unsure what to make of it
"You Tried to excecute a query that does not include the specified
expression 'Dated as part of an aggregate function."**
D Stanley solved my question with the following query
SELECT DateValue(Dated) AS Dated, [Level 1 reason], SUM(Duration) AS Mins
FROM Downtime
GROUP BY DateValue(Dated), [Level 1 reason]
In Access you ace use the DateValue function to remove the time from a date column:
SELECT DateValue(Dated) Dated, [Level 1 reason], SUM(Duration) AS Mins
FROM Downtime
GROUP BY DateValue(Dated), [Level 1 reason]
It seems like you want to remove the time component. How to do that varies between database systems. In SQL Server it would be:
SELECT DATEADD(day,DATEDIFF(day,0,Dated),0), [Level 1 reason],
SUM(Duration) AS Mins
FROM Downtime
GROUP BY DATEADD(day,DATEDIFF(day,0,Dated),0), [Level 1 reason]
This works because 0 can be implicitly converted to a date (01/01/1900 at midnight), and DATEADD and DATEDIFF only work in integral parts of the datepart (here, day). So, this is "how many complete days have occurred since 01/01/1900 at midnight?" and "Let's add that same number of days onto 01/01/1900 at midnight" - which gives us the same date as the value we started with, but always at midnight.
For Access, I think you have to quote the datepart (day becomes "d"). I'm not sure if the 0 implicit conversion still works - but you can just substitute any constant date in all for places I've used a 0 above, something like:
SELECT DATEADD("d",DATEDIFF("d","01/01/1900",Dated),"01/01/1900"),
[Level 1 reason],
SUM(Duration) AS Mins
FROM Downtime
GROUP BY DATEADD("d",DATEDIFF("d","01/01/1900",Dated),"01/01/1900"),
[Level 1 reason]
I guess in access it would be:
SELECT CDate(Int(Dated)) , [Level 1 reason],
SUM(Duration) AS Mins
FROM Downtime
GROUP BY CDate(Int(Dated)) , [Level 1 reason];

Query to find late parts shipped and list them by quarter

I am having the toughest time getting a query created for this scenario:
I need to list all parts that were late and sum them by quarter.
Here is the query that I have so far:
SELECT DISTINCTROW
Format$([InvoiceSub].[Date_Shipped],'\Qq yyyy') AS [Date_Shipped By Quarter]
, Sum(InvoiceSub.Quantity) AS [Sum Of Quantity]
FROM
InvoiceSub
INNER JOIN
Job_Book_Sub
ON (InvoiceSub.[Job #] = Job_Book_Sub.[Job #])
AND (InvoiceSub.[LineItem#] = Job_Book_Sub.[LineItem#])
GROUP BY
Format$([InvoiceSub].[Date_Shipped],'\Qq yyyy')
, Year([InvoiceSub].[Date_Shipped]) * 4 + DatePart('q', [InvoiceSub].[Date_Shipped]) -1;
This query works fine to display all parts that were shipped by quarter. However, I want to see all parts that were shipped LATE by quarter.
I have a field in a table named: Job_Book_Sub, and that field is [LineItem_DueDate]. I want to use that in the query so that it will display all parts that were late ([date_shipped] > [lineitem_duedate]). The [date_shipped] is the actual date the parts were shipped, [lineitem_duedate] is the date the parts were due. I know that I need to incorporate these two fields into the query, I just don't know how.
Can someone please show me how to do this? If I add the [LineItem_DueDate] to the query, then it no longer sums the dates by quarter but instead lists every record (so instead of having 45 records with different quarters over the past 10+ years, I all of a sudden have 13000+ records because it is listing each record with date_shipped in the query.
Can someone help please?
Try adding your filter in a WHERE clause:
SELECT DISTINCTROW
Format$([InvoiceSub].[Date_Shipped],'\Qq yyyy') AS [Date_Shipped By Quarter]
, Sum(InvoiceSub.Quantity) AS [Sum Of Quantity]
FROM
InvoiceSub
INNER JOIN
Job_Book_Sub
ON (InvoiceSub.[Job #] = Job_Book_Sub.[Job #])
AND (InvoiceSub.[LineItem#] = Job_Book_Sub.[LineItem#])
WHERE
Job_Book_Sub.[date_shipped] > Job_Book_Sub.[lineitem_duedate]
GROUP BY
Format$([InvoiceSub].[Date_Shipped],'\Qq yyyy')
, Year([InvoiceSub].[Date_Shipped]) * 4 + DatePart('q', [InvoiceSub].[Date_Shipped]) -1;