Related
I would like some help with the filter for summing Quarterly data.
For Yearly data I have added the formula.
For Quarterly data, I have hard coded for now but need to get the system to calculate.
So for example next quarter which will be Quarter 3, I need to calculate figures for current year/current quarter (summing figures for 3 months in that quarter)
SNIPPET of filter code
WHERE [Status] = 'Complete'
AND (YEAR([datefield]) = YEAR(GETDATE()) - 1
OR YEAR([datefield]) = YEAR(GETDATE()) - 2
OR YEAR([datefield]) = YEAR(GETDATE())
AND MONTH([datefield]) IN(4, 5, 6)) --Apr/May/June.
Sorry for providing an incomplete answer. I have thought of this after I've answered.
SELECT *
FROM table
WHERE [Status] = 'Complete'
AND [datefield] BETWEEN CONVERT(date, DATEADD(M, -2, DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE())))
AND EOMONTH(DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE()))
Explanation:
For the filter to be accurate, you need to get the first day and last day of the month.
First Day:
Get current date:
SELECT GETDATE()
2018-09-06 17:03:35.467
Get current date minus 1
SELECT DATEADD(D, -1, GETDATE())
2018-09-05 17:03:35.467
Subtract "current date minus 1" (the above result) to the current date.
SELECT DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE())
2018-09-01 17:03:35.467
Get date part only:
SELECT CONVERT(date, DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE()))
2018-09-01
Last Day:
Same as getting the first day, but changing CONVERT to EOMONTH since the latter already returns the result as date part only
SELECT EOMONTH(DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE()))
2018-09-30
So you now have
SELECT CONVERT(date, DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE()))
,EOMONTH(DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE()))
2018-09-01
2018-09-30
Get the previous 2 months from the current month.
SELECT CONVERT(date, DATEADD(M, -2, DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE())))
Notice that I just added DATEADD(M, -2, ) to the First Day value.
Combine the first day of 2 months ago and the last day of the current month you get
SELECT CONVERT(date, DATEADD(M, -2, DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE())))
,EOMONTH(DATEADD(D, -DAY(DATEADD(D, -1, GETDATE())), GETDATE()))
2018-07-01
2018-09-30
I'm pretty new to MSSQL and was wondering if someone could help me convert the following where statement from looking at previous week to previous month.
ks.report_date BETWEEN (convert(varchar(113), (DATEADD(day, (-1 * DATEPART(dw, (dateadd(week, -1, getdate())))) + 1, (dateadd(week, -1, getdate())))), 101))
AND (convert(varchar(113), (DATEADD(day, (-1 * DATEPART(dw, (dateadd(week, -1, getdate())))) + 7, (dateadd(week, -1, getdate())))), 101))
SQL Server has a function called EOMonth() that will take a date and give you the end of the month containing that date. You can then use DATEADD to subtract months from that value to get the last day of previous months. Lastly, use DATEADD again to add 1 day to get the first day of the month. Here is an example.
BETWEEN DATEADD(DAY, 1, DATEADD(MONTH, -2, EOMONTH(GETDATE())))
AND DATEADD(MONTH, -1, EOMONTH(GETDATE()))
If you're using an earlier version than SQL Server 2012 then this would work:
BETWEEN DATEADD(MONTH, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
AND DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0))
One of my clients defines (for strange financial reasons) a financial month as a period of time that begins the Wednesday immediately after the last Tuesday of a Month (inclusive) and lasts until the last tuesday of the following month (inclusive).
I need to find the start of the last and the current financial month.
Some examples:
if today is September 23rd 2015 i need to get July 29th and August 26th because the current financial month goes from August 26th to September 29th.
If today is September 30th 2015 I need to get August 26th to September 30th.
I have different clients with different definitions and this means that some of them are using Wednesday and others are using Monday so i need this day to be a parameter, like Monday = 1 and Wednesday = 3. I call it FDOM, FirstDayOfMonth.
My work so far focused on using the formulas i found around with first and last days of current and last month, modified to take into account FDOM. I managed to get last Wednesday of Last Month but this sometimes is not correct because I am considering a day of the month that belongs to a solar month but also to the next financial month, like September 30th belongs to solar September but to Financial October, as financial October begins September 30th.
DECLARE #BASE AS DateTime = '19000101 00:00'
DECLARE #FDOM AS INT = 3 --Wednesday
DECLARE #Datevalue AS DATE = GETDATE()
SET DATEFIRST #FDOM
select DATEADD(D,1-(DATEPART(dw,DATEADD(D,-1,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #Datevalue) , #BASE)))),DATEADD(D,-1,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #Datevalue) , #BASE)))
This gives me the first wednesday after the last tuesday of last month and this would be correct from September 1st to September 29th (it gives August 26th) as "the beginning of the current financial month". But it would be wrong on September 30th as it should give September 30th and also wrong from August 26th till the end of August as it should give August 26th but instead gives July 29th.
I think this answers your requirements. Its quite long but hopefully, by breaking things out and naming things, I'm making it clear how we get to the final answer, and so if it's not quite right, it can be adapted:
declare #FDOM int
set #FDOM = 3 --Wednesday. 0 = Sunday, 6 = Saturday
declare #KnownDay datetime
set #KnownDay = DATEADD(day,#FDOM - 1,'20150301') --Offset from a "known good" Sunday to the day before FDOM
declare #EOLastDec datetime
set #EOLastDec = DATEADD(year,DATEDIFF(year,'20010101',GETDATE()),'20001231')
declare #Today datetime
set #Today = DATEADD(day,DATEDIFF(day,0,GETDATE()),0) --You can change this to test other key dates
;With Numbers(n) as (--If you have a numbers table, you can skip this CTE
select ROW_NUMBER() OVER (ORDER BY so1.object_id) - 1
from sys.objects so1 cross join sys.objects so2
), LastOfMonths as (
select DATEADD(month,n,#EOLastDec) as LOM
from Numbers
where n between 0 and 13
), LastImportant as (
select DATEADD(day,-n,LOM) as EOFMonth
from LastOfMonths cross join Numbers
where n between 0 and 6 and
DATEPART(weekday,DATEADD(day,-n,LOM)) = DATEPART(weekday,#KnownDay)
)
select DATEADD(day,1,li0.EOFMonth) as StartOfMonth,DATEADD(day,1,li1.EOFMonth) as EndOfMonth
from
LastImportant li1
cross join
LastImportant li2
left join
LastImportant li1_anti
on
li1.EOFMonth < li1_anti.EOFMonth and
li1_anti.EOFMonth <= #Today
left join
LastImportant li2_anti
on
li2.EOFMonth > li2_anti.EOFMonth and
li2_anti.EOFMonth >= #Today
inner join
LastImportant li0
on
li0.EOFMonth < li1.EOFMonth
left join
LastImportant li0_anti
on
li0_anti.EOFMonth < li1.EOFMonth and
li0.EOFMonth < li0_anti.EOFMonth
where
li1.EOFMonth <= #Today and
li2.EOFMonth >= #Today and
li1_anti.EOFMonth is null and
li2_anti.EOFMonth is null and
li0_anti.EOFMonth is null
Hopefully, the CTEs are reasonably explanatory. We generate a numbers table, and then we calculate the last day of each month, and from there, we step up to 6 days backwards to locate a day of the right type (i.e. a Tuesday, if #FDOM is 3)
I originally had a simpler final query using just li1 and li2 (and li1_anti and li2_anti), but realised that the query was just finding the current financial month - so I've added another couple of joins (using li0 and li0_anti) to find the start of the previous financial month.
Calculate the start date from previous month and the last day from current month and used a CTE to generate all dates between them. Later, get the MAX weekday from both months.
DECLARE #CurrentDate DATE = '2015-08-23'
DECLARE #StartDate DATE,
#EndDate DATE,
#MonthEnd INT = 3
-- Get the first day from previous month and last day from current month
SELECT #StartDate = DATEADD(MONTH , DATEDIFF(MONTH, 0, #CurrentDate)-1, 0),
#EndDate = DATEADD(SECOND,-1,
DATEADD(MONTH , DATEDIFF(MONTH, 0, #CurrentDate)+1,0))
;WITH Calendar AS
( -- Generate all dates between #StartDate and #EndDate
SELECT #StartDate [Date]
UNION ALL
SELECT DATEADD(D, +1, Calendar.[Date])
FROM Calendar
WHERE Calendar.[Date] < #EndDate
)
SELECT DATEADD(DAY, +1, MAX(StartDate.[Date])) StartDate,
DATEADD(DAY, +1, MAX(EndDate .[Date])) EndDate
FROM Calendar StartDate,
Calendar EndDate
WHERE -- Get the max weekday from previous month
DATEPART(MONTH , StartDate.[Date]) = DATEPART(MONTH, #StartDate) AND
DATEPART(WEEKDAY, StartDate.[Date]) = #MonthEnd AND
-- Get the max weekday from current month
DATEPART(MONTH , EndDate .[Date]) = DATEPART(MONTH, #EndDate) AND
DATEPART(WEEKDAY, EndDate .[Date]) = #MonthEnd
Try this. You can use EOMONTH function to get the end of month on Sql Server 2012 or above.
Click to see the fiddle demo.
DECLARE #date DATETIME = GETDATE()
DECLARE #LastMonthEnd DATETIME = DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, #date), 0))
DECLARE #CurrentMonthEnd DATETIME = DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, #date) + 1, 0))
SET DATEFIRST 1
;WITH CTE1 AS
(
SELECT 1 number, DATEPART(WEEKDAY, #LastMonthEnd) FirstDay,
DATEPART(WEEKDAY, #CurrentMonthEnd) LastDay
UNION ALL
SELECT 1+number, DATEPART(WEEKDAY, DATEADD(DAY, -number, #LastMonthEnd)),
DATEPART(WEEKDAY, DATEADD(DAY, -number, #CurrentMonthEnd))
FROM CTE1
WHERE number < 7
)
SELECT DATEADD(DAY, -(SELECT Number FROM CTE1 WHERE FirstDay = 3), #LastMonthEnd) StartDate,
DATEADD(DAY, -(SELECT Number FROM CTE1 WHERE LastDay = 3), #CurrentMonthEnd) EndDate
After a lot of effort I managed to find an expression that DOES NOT use CTE as i am not sure i can't use CTE in all the places i will have to employ this.
So basically first i understand with a CASE if the date i am considering is before or after the last Wednesday of the Month it belongs to. Then i return the last wednseday of two and of one month ago OR the last wednesday of one month ago and of this month.
This works also changing FDOM and i tested it for several months of this year. It seems to always work.
Probably the use of EOMonth would shorten it but i have to verify i can use it in my server.
I am sorry i just specified as a requirement that i can't use a CTE only in the comments but thank you for your help
DECLARE #datevalue AS Datetime = getdate()
DECLARE #BASE AS DateTime = '19000101 00:00'
DECLARE #FDOM AS INT = 3 --1 is for Monday
SET DATEFIRST #FDOM
SELECT CASE WHEN (#datevalue < DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 1, #BASE))),DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 1, #BASE)))
THEN(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) - 1, #BASE))),DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) - 1, #BASE)))
ELSE(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) - 0, #BASE))),DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) - 0, #BASE)))
END AS [Start of Last Financial Month]
,CASE WHEN (#datevalue < DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 1, #BASE))),DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 1, #BASE)))
THEN(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 0, #BASE))),DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 0, #BASE)))
ELSE(DATEADD(D, 1-(DATEPART(dw,DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 1, #BASE))),DATEADD(MONTH, DATEDIFF(MONTH, #BASE, #datevalue) + 1, #BASE)))
END AS [Start of Current Financial Month]
I am developing a report using SQL and SSRS that gives a day by day breakdown of stats from the 1st of the month to the previous day.
However, on the 1st of the month the report comes up blank when I need it to show the previous months information (e.g. on the 1st of February I want a report that gives me a day by day breakdown of January from the 1st to 31st.
I tried the following case statement in the SQL where clause to see if it would fix the issue but it doesn't seem to work:
(dIntervalStart BETWEEN dbo.DateAndTime(CASE WHEN DAY(GEtDate()) = 1 THEN DATEADD(mm, DATEDIFF(mm, 0, GETDATE() - 1), 0) ELSE DATEADD(mm, DATEDIFF(mm, 0, GETDATE()), 0) END, '00:00:00')
Is there something else that might work?
declare #StartOfMOnth bit
declare #startDate date
declare #endDate date
select #StartOfMOnth =
case when datepart(dd, getdate()) <> 1 then 0
else 1
end
IF (#StartOfMOnth = 0) --If not start of month
BEGIN
SELECT #startDate = DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) --First day of current month
SELECT #endDate = DATEADD(DD, -1, GETDATE())--Previous day
END
ELSE --If start of month
BEGIN
SELECT #startDate = DATEADD(MONTH, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)) --First day of last month
SELECT #endDate = DATEADD(DD, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0))--Last day of last month
END
--Once you have start and end dates, do what needs to be done in the dataset
The query below grabs the max date from column Time_Stamp as StartDate from Survey. Adding 90 days to it for EndDate. Then creating 2 more ranges with 90 day intervals by just adding more to the original EndDate.
I'm trying to have the StartDate fall within 4 buckets of either Jan1st, April1st, July1st, or Oct1. If the Max Time_Stamp is before 1 of these dates then that will be the first StartDate of my ranges...So for my example below, the max Time_Stamp is June4th so the StartDate needs to be July 1st. Is this doable within sql server?
Time_Stamp for Hospital1
Time_Stamp
-----------
2014-06-04 16:01:14.000
2014-06-04 15:55:33.000
2014-06-04 15:45:05.000
2014-06-04 15:36:15.000
2014-06-04 15:00:34.000
2014-06-04 14:35:24.000
2014-06-04 14:04:50.000
2014-06-04 13:46:55.000
2014-06-04 13:23:57.000
2014-06-04 11:27:51.000
Current output:
StartDate EndDate
----------- -----------
Jun 4 2014 Sep 2 2014
Sep 3 2014 Dec 2 2014
Dec 3 2014 Mar 3 2015
query
WITH Start AS
(
SELECT
MAX(Time_Stamp) as StartDate,
DATEADD(day, 90, MAX(Time_Stamp)) as EndDate
FROM Survey
WHERE MainHospital = 'Hospital1'
),
Results AS
(
SELECT StartDate, EndDate from Start
UNION
SELECT DATEADD(DAY, 1, EndDate), DATEADD(day, 91, EndDate) FROM Start
UNION
SELECT DATEADD(DAY, 92, EndDate), DATEADD(day, 182, EndDate) FROM Start
)
SELECT LEFT(StartDate,11) AS StartDate, LEFT(EndDate,11) AS EndDate FROM Results
Just an update, this gives me what I need for the 1st StartDate...
--Return first day of next quarter
SELECT DATEADD(qq, DATEDIFF(qq, 0, MAX(Time_Stamp)) + 1, 0)
FROM Survey
WHERE MainHospital = 'Hospital1'
DECLARE #Year DATE = '2013-01-01'
DECLARE #Quarter INT = 1;
SELECT DATEADD(QUARTER, #Quarter - 1, #Year) ,
DATEADD(DAY, -1, DATEADD(QUARTER, #Quarter, #Year))
You can use DATEPART(QUARTER, #Date) to figure out which quarter the record being selected and then you can use this query to find the begin/end dates of that quarter.
Use it like this:
SELECT DATEADD(QUARTER, DATEPART(QUARTER, Time_Stamp) - 2, DATEADD(YEAR, DATEDIFF(YEAR, 0, Time_Stamp), 0)) AS StartDate,
DATEADD(SECOND, -1, DATEADD(QUARTER, DATEPART(QUARTER, Time_Stamp) - 1, DATEADD(YEAR, DATEDIFF(YEAR, 0, Time_Stamp), 0))) AS EndDate
FROM Hospital1
It seems that you are just trying to calculate the quarter of your date, Am i correct?
If so, you can just use:
SELECT DATENAME(Quarter, CAST(CONVERT(VARCHAR(8), GETDATE()) AS DATETIME)) as Quarter
to calculate a quarters date ranges:
select DATEADD(qq, datediff(qq, 0, getdate()),0) as first
select dateadd(dd, -1, DATEADD(qq, datediff(qq, 0, getdate()) +1, 0)) as last