SQL Count of Instances of Date in MS Access - sql

So I've got a table of data in the link below (an excel spreadsheet in a zip file):
https://drive.google.com/file/d/0B4mYzBk2sry_eDg5NVhTcmtXTTg/view?usp=sharing
It has been sorted and ordered as 'Date Issued - Oldest to Most Recent'.
What I'm after is a solution that gives me a count of instances an issue was made in a month for the Financial Year (01/07/2015 to 30/06/2016).
For instance, referring to the data, July 2015 had 13 issues for that month, August 2015 had 16 issues, September 2015 had 9 issues, etc.
I've created the code below to generate the data provided in the spreadsheet:
SELECT tblCustomerNames_1.CustomerName AS [Issued To], tblCustomerNames.CustomerName AS [Issued By], tblIssueSheets.DateIssued AS [Date Issued], Count(tblMarkHistory.MarkHistoryID) AS [Marks Issued]
FROM (tblCustomerNames AS tblCustomerNames_1 INNER JOIN (tblIssueSheets INNER JOIN tblCustomerNames ON tblIssueSheets.IssuedBy = tblCustomerNames.CustomerID) ON tblCustomerNames_1.CustomerID = tblIssueSheets.CustomerID) INNER JOIN tblMarkHistory ON tblIssueSheets.IssueID = tblMarkHistory.IssueID
WHERE (((tblIssueSheets.DateIssued)>=[DateFrom] And (tblIssueSheets.DateIssued)<[DateTo]) AND ((tblCustomerNames.CustomerID)=2447))
GROUP BY tblCustomerNames_1.CustomerName, tblCustomerNames.CustomerName, tblIssueSheets.DateIssued
ORDER BY tblCustomerNames_1.CustomerName;
Please note that data has been deliberately left out as I figured the information I've provided thus far is more important to what is needed. If it isn't sufficient, let me know and I'll provide the rest of the data.
A result table of the totals of Date Issued by month and year is what I'm after.
I'm not sure how to go about this at all. Any assistance would be appreciated.

Using your saved query as source, it could be:
Select
Month([Date Issued]) As [Month],
Count(*) As Issues
From
YourQuery
Where
[Date Issued] Between #2015/07/01# And #2016/06/30#
Group By
Month([Date Issued])
Order By
Year([Date Issued]),
Month([Date Issued])
If Month# should follow the financial year, use a generic function to offset the dates from the calendar year:
Public Function DateFinancial( _
ByVal datDate As Date) _
As Date
' Number of months from start of calendar year to start of financial year.
Const clngMonthOffset As Long = 6
Dim datFinancial As Date
datFinancial = DateAdd("m", -clngMonthOffset, datDate)
DateFinancial = datFinancial
End Function

Related

SQL case expression to run report based on Fiscal Year

I'm attempting to create some reports in my organization's new Help Desk system, which uses sql for its database and reporting systems. I've never interacted with sql before, so I'm having to make this up as I go. I've been able to cannibalize most of what I need from other, pre-made reports, but I'm running into a road block getting the report to group by Fiscal Year and not Calendar Year. The report I'm currently working on is meant to calculate the average time to closure on tickets. The original version grouped and ordered everything by the calendar year, and appeared to be working. However, when I try to retrofit the code to group/sort based on a July 1-June 30 Fiscal Year using the suggested method in this answer (as shown in my report code below), I'm getting the error, "The multi-part identifier "htblticket.date could not be bound."
I also tried some variants on this answer, with even less success. Does anyone have some suggestions on what I might be screwing up here, or some ideas on better ways to approach this? I'd appreciate any help/enlightenment you can provide!
Select Top 1000000 Case
When DatePart(mm, htblticket.date) > 6 Then DatePart(yyyy, htblticket.date)
+ 1
Else DatePart(yyyy, htlbticket.date)
End As [Fiscal Year],
Convert(Decimal(9,2),Avg(Cast(DateDiff(ss, htblticket.date,
ClosedDate.CloseDate) As decimal) / 86400)) As AverageDays
From htblticket
Inner Join (Select Top 1000000 htblticket.ticketid,
Max(htblhistory.date) As CloseDate
From htblticket
Inner Join htblticketstates On htblticketstates.ticketstateid =
htblticket.ticketstateid
Inner Join htblhistory On htblhistory.ticketid = htblticket.ticketid
Inner Join htblticketstates htblticketstates1 On
htblhistory.ticketstateid = htblticketstates1.ticketstateid
Inner Join htblhistorytypes On htblhistorytypes.typeid =
htblhistory.typeid
Where htblticketstates.statename = 'Closed' And
htblticketstates1.statename = 'Closed' And
htblhistorytypes.name In ('Status changed',
'Note added and state changed', 'Internal note added and state changed')
Group By htblticket.ticketid) As ClosedDate On ClosedDate.ticketid =
htblticket.ticketid
Group By Case
When DatePart(mm, htblticket.date) > 6 Then DatePart(yyyy, htblticket.date)
+ 1
Else DatePart(yyyy, htlbticket.date)
End
Order By [Fiscal Year] Desc
Your question boils down to how to group by the (Australian) financial year July-June.
One simple approach would be to create a column “financial_year_start” which is an expression that subtracts 6 months from each date and extracts the year of the result, then group by that.

SQL - Get data between two dates grouped by week

This question might have been solved many times or even asked many times. But as I am not a savvy in SQL, I am not able to figure out things found on the internet. Like I am not able to tweak Queries from the Internet to my needs.
And here comes my need
I have a Table named Orders Containing Fields like OrderId, OrderDate etc.
I need to generate an Excel Sheet. The sheet will have the count of orders grouped by week.
(Like how many orders placed within that week)
The user can choose the year in which he/she needs the report for.
So if the user chooses the current year then I need to generate an excel report containing data from Jan 1 to today grouped by week.
If the user chooses any other year(maybe previous years) then I need to generate a report containing all the data for that year grouped by week.
Currently, I am looking for an SQL query that returns data like this(expected output)
Week Date Range Total No of Orders
-----+--------------------------+-------------------
week#1 2018-01-01 - 2018-01-07 10
week#2 2018-01-08 - 2018-01-14 0
week#3 2018-01-15 - 2018-01-21 1
How can I write a query to achieve the same?
Looking for expert advice...
You need to use CTE recursive write calendar by week number,then Orders LEFT JOIN on CTE calendar table get COUNT.
Note:
variable #Dt mock which year you want to start.
Query look like this.
DECLARE #Dt date = '2018-01-01'
;WITH CTE(Dt,maxD) AS (
SELECT DATEPART(ww,#Dt) Dt, DATEPART(ww,MAX(OrderDate)) maxD
FROM Orders
UNION ALL
SELECT (Dt +1) Dt,maxD
FROM CTE
WHERE (Dt +1) <= maxD
)
SELECT CONCAT('week#',c.Dt) 'week',
CONCAT(
CONVERT(char(10),dateadd(week,c.Dt-1, DATEADD(wk, DATEDIFF(wk,-1,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)), 0)),126)
,'-'
, CONVERT(char(10),dateadd(week,c.Dt, DATEADD(wk, DATEDIFF(wk,-1,DATEADD(yy, DATEDIFF(yy,0,getdate()), 0)), 0)),126)) 'Date Range',
COUNT(o.OrderDate) 'Total No of Orders'
FROM CTE c
LEFT JOIN Orders o on c.Dt = DATEPART(ww,o.OrderDate)
GROUP BY c.Dt
sqlfiddle:http://sqlfiddle.com/#!18/8f089/40

SQL Difference Between Current Year and Last Year. If Last Year Data Does Not Exist Include Current Year

In a previous post I got help finding incremental sales. The query works great. I added the breakout by product. The issue I’m having is that I need to show new products being sold. If the product did not exist last year, but we are selling it this year; then it should show up in the data table.
I tried use a CASE statement in the WHERE, but it was causing a lot of duplication of the data. I was thinking something like what is below. How do I go about including items that are only in the current year? Thank you for your help, its greatly appreciated.
Not Working Where Clause
WHERE
Ym.Project =
CASE
WHEN ymprev.Project IS NULL THEN ym.Project
ELSE ymprev.Project
END
Below is the working query.
WITH ym as(
SELECT
Product
,SUM(Sales) AS Sales
,MONTH(Date) AS Month
,YEAR(Date) AS Year
FROM SalesTable
GROUP BY
YEAR(Date)
,MONTH(Date)
,Product
)
SELECT
ymprev.Project AS PrevProject
,ym.Product
,ym.Sales
,ymprev.Sales AS PreviousSales
,(ym.Sales - ymprev.Sales) AS IncrementalSales
,ymprev.Month AS PreviousMonth
,ymprev.Year AS PreviousYear
,ym.Month
,ym.Year
FROM ym
JOIN ym ymprev on
ymprev.Year = ym.Year
AND ymprev.Month = ym.Month
AND ymprev.Product = ym.Product
ORDER BY
ym.Year
,ym.Month
Your query is implicitly using an INNER JOIN - this means that you will only see values that have a match in both datasets, just as you describe.
Try changing your FROM clause to
FROM ym
LEFT JOIN
ym ymprev on
ymprev.Year = ym.Year
AND ymprev.Month = ym.Month
AND ymprev.Product = ym.Product
You will also need to incorporate similar logic in any values that include data elements from the previous year's query. For example, ,(ym.Sales - ymprev.Sales) AS IncrementalSales will need to be turned into ,(ym.Sales - ISNULL(ymprev.Sales,0)) AS IncrementalSales or it will return NULL for any records that only exist in the current year.
Your posted query doesn't include the Project field in your CTE, so I can't tell exactly how that works, but the posted data should get you started.

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;

Optimizing NOT IN query in Access SQL

I am new to Access and am using Access 2007.
I am doing a simple query on a database that has a list of customers who visits a workshop.
I want to send out reminders to the customers for their servicing 3 months from the last time they visited. I have created a query to be able to return me the list of customers who has visited 3 months from the current month. For example, if it is May now, 3 months ago would be March (inclusive of May).
However, customers who visited 3 months ago may have visited again 2 months ago. For example, customer A came in March and April. His last visit was in April, and hence, should not appear in the result if I were to run the query in May, as his reminder should only be sent out in June.
My query has taken care of this, however, it is rather slow. It takes some time for it to load in Access. Any help would be appreciated in optimizing it.
The only important field here is Invoice.DebCode which is the customersID in the database. There is another table DEBTOR, which is the table of customers together with their particulars.
I used the INNER JOIN as I need to display the customer(Debtor) address and particulars in the result.
SELECT Invoice.InvNo, Invoice.InvDate, Invoice.DebCode, Debtor.DebName, Debtor.AddL1, Debtor.AddL2, Debtor.AddL3, Invoice.CarNo, Invoice.ChaNo, Invoice.ExcReason
FROM Debtor
JOIN Invoice ON Debtor.DebCode = Invoice.DebCode
WHERE Year(InvDate) = Year(Now())
AND Month(InvDate) = Month(Now()) - 2
AND Invoice.DebCode NOT IN (SELECT Invoice.DebCode
FROM Invoice
WHERE Year(InvDate) = Year(Now())
AND ( (Month(InvDate) = Month(Now()) -1)
OR (Month(InvDate) = Month(Now())) )
You can dramatically speed up your query by adjusting your WHERE clauses so that the comparisons get done directly against the date field (ie, without passing it through the Month() and Year() functions). Doing it this way allows the Jet engine to make use of the index you have on the Invoice.InvDate field (you do have that field indexed, right?).
SELECT I.InvNo, I.InvDate, I.DebCode, D.DebName, D.AddL1, D.AddL2, D.AddL3,
I.CarNo, I.ChaNo, I.ExcReason
FROM Debtor AS D
INNER JOIN Invoice AS I
ON D.DebCode = I.DebCode
WHERE I.InvDate Between DateSerial(Year(Now()), Month(Now()) - 2, 1)
And DateSerial(Year(Now()), Month(Now()) - 1, 0)
AND I.DebCode NOT IN
(SELECT Invoice.DebCode FROM Invoice
WHERE Invoice.InvDate > DateSerial(Year(Now()), Month(Now()) - 1, 0))
What about something like:
SELECT a.debcode, a.debname, a.debstuff, b.most_recent AS last_over_three_months
FROM debtor AS a INNER JOIN
(
SELECT debcode, Max(invdate) AS most_recent
FROM invoice
GROUP BY debcode
)
as b
ON a.debcode= b.debcode
WHERE (month(now()) - Month(most_recent) >2);
You will have to tweak for your stuff, but the idea is a subquery that select the most recent customer visit and then selects from that only the records that meet your month criteria.
I managed to speed up the query thanks to mwolfe02 suggestion.
For archiving and completion sake, I will explain my sql statements below.
SELECT I.InvNo, I.InvDate, I.DebCode, D.DebName, D.AddL1, D.AddL2, D.AddL3,
I.CarNo, I.ChaNo, I.ExcReason
FROM Debtor AS D
INNER JOIN Invoice AS I
ON D.DebCode = I.DebCode
WHERE I.InvDate Between DateSerial(Year(Now()), Month(Now()) - 2, 1)
And DateSerial(Year(Now()), Month(Now())- 1, 0)
AND I.DebCode NOT IN
(SELECT Invoice.DebCode FROM Invoice
WHERE Invoice.InvDate Between DateSerial(Year(Now()), Month(Now()) - 1, 1)
And DateSerial(Year(Now()), Month(Now()), 0))
I edited the bottom sub query as mwolfe checked only for customers in the current month. The customers eligible for a reminder only if they came 3 months ago. That is to say, they cannot have visited between the current month and the month before.
For example, customer A visited in April and May. The current month is June, thus he is not eligible for the reminder, as his last visit was in May.
Customer B visited in April and June, thus he is not eligible for the reminder, as his last visit was in June.
Hence, the english version of the query would be:
Get customers who came 3 months ago from the last day of the current month and did not come in the current month and the month before.
I hope this helps anyone who has the same problem.
As darkjh and mikey suggested, we can "select the most recent customer visit and then selects from that only the records that meet your month criteria."
Thanks all!