Count ISO_WEEK between two dates (potentially spanning across years) - sql

This may be a fairly simple question but I can't find a simple solution anywhere. Is there a way to count ISO_WEEK between two dates (which also may span over multiple years) without subtracting the ISO_WEEK values themselves?
If I subtract the number of ISO weeks between the below I get -47
2024-12-01 = W48
2024-12-31 = W01
The expected result should be 5
If I subtract the number of ISO weeks between the below I get -47
2022-01-01 = W52
2022-01-31 = W05
The expected result should be 6
If I subtract the number of ISO weeks between the below I get 0
2022-01-01 = W52
2022-12-31 = W52
The expected result should be 53
If I subtract the number of ISO weeks between the below I get -3
2022-12-31 = W01
2023-01-26 = W04
The expected result should be 5
Here is two portions of SQL I am using to test:
The intention here is to calculate number of ISO weeks in the previous month for billing purposes. A condition has been added to remove 1 week from previous month should the week have already been billed in the previous iteration using conditional logic surrounding the first Sunday of that month.
DECLARE #D DATE = '2025-01-01'
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0) AS FOM
, DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)) AS FOM_ISOWEEK#
, DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #D)-1, -1))-DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0))+1 AS ISOWEEK_COUNT
, DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #D)-1, -1)) AS EOM_ISOWEEK#
, DATEADD(MONTH, DATEDIFF(MONTH, -1, #D)-1, -1) AS EOM
, DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 0 - DATEPART(DAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)), DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0))), 6) AS FSUNDAY
, CASE WHEN DATEDIFF(DAY, (DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)), (DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 0 - DATEPART(DAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)), DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0))), 6)))+1 < 7
THEN DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #D)-1, -1))-DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0))
ELSE DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #D)-1, -1))-DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0))+1 END AS [SUM]
DECLARE #DD DATE = '2022-02-01'
SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0) AS FOM
, DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0)) AS FOM_ISOWEEK#
, DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #DD)-1, -1))-DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0))+1 AS ISOWEEK_COUNT
, DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #DD)-1, -1)) AS EOM_ISOWEEK#
, DATEADD(MONTH, DATEDIFF(MONTH, -1, #DD)-1, -1) AS EOM
, DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 0 - DATEPART(DAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0)), DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0))), 6) AS FSUNDAY
, CASE WHEN DATEDIFF(DAY, (DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0)), (DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 0 - DATEPART(DAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0)), DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0))), 6)))+1 < 7
THEN DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #DD)-1, -1))-DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0))
ELSE DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, -1, #DD)-1, -1))-DATEPART(ISO_WEEK,DATEADD(MONTH, DATEDIFF(MONTH, 0, #DD)-1, 0))+1 END AS [SUM]
Everything works except when the subtraction spans over multiple years. I have provided two examples of this occurence above.
UPDATE
I have simplified somewhat and found a reasonable workaround here. Updated logic below:
DECLARE #D DATE = '2025-01-01'
DECLARE #FOM DATE = DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)
, #EOM DATE = DATEADD(MONTH, DATEDIFF(MONTH, -1, #D)-1, -1)
SELECT #FOM AS FOM
, DATEPART(ISO_WEEK,#FOM) AS FOM_ISOWEEK#
, DATEDIFF(dd,0,#EOM)/7 - DATEDIFF(dd,0,#FOM)/7 +1 AS ISOWEEK_COUNT
, DATEPART(ISO_WEEK,#EOM) AS EOM_ISOWEEK#
, #EOM AS EOM
, DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 0 - DATEPART(DAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)), DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0))), 6) AS FSUNDAY
, CASE WHEN DATEDIFF(DAY, (DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)), (DATEADD(WEEK, DATEDIFF(WEEK, 0,DATEADD(DAY, 0 - DATEPART(DAY, DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0)), DATEADD(MONTH, DATEDIFF(MONTH, 0, #D)-1, 0))), 6)))+1 < 7
THEN DATEDIFF(dd,0,#EOM)/7 - DATEDIFF(dd,0,#FOM)/7
ELSE DATEDIFF(dd,0,#EOM)/7 - DATEDIFF(dd,0,#FOM)/7 +1 END AS [SUM]
This update produces the desired output.

https://social.msdn.microsoft.com/Forums/sqlserver/en-US/604052a8-b024-41a5-8bac-1c657d9f6025/calculate-number-of-weeks-between-dates?forum=transactsql
This helped. I have edited my question with an UPDATE to show it in use.

Related

Joining another tables results to add to a existing query

I want to add RuntimePercentage column to my existing Uptime query for a report. Below is the current queries I use now. To do this I need to join another table results to make it happen but I haven't been able to find a solution. The where clause gives me a error because UptimeMin is only in table a.
How RuntimePercentage is calculated as:
(IdletimeMin/60) IdletimeHours - Total current monthly hours /UptimeMin/60 UptimeHours = RuntimePercentage
Current uptime query
SELECT
a.StackNbr,
(SUM(a.UptimeMin)) / 60 UptimeHours,
ROUND((SUM(a.UptimeMin) / ((DATEDIFF(d, DATEADD(month, DATEDIFF(month, 0, getDate()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60)) * 100, 2) UptimePercentage,
(((DATEDIFF(d, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60) - SUM(a.UptimeMin)) / 60 DowntimeHours,
ROUND((((DATEDIFF(d, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60) - SUM(a.UptimeMin)) / ((DATEDIFF(d, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60) * 100, 2) DowntimePercentage,
COUNT(UptimeMin) Count
FROM
IngStackerUptime a
WHERE
a.UptimeMin > 0
AND a.DateTm BETWEEN DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
AND DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)
GROUP BY
a.StackNbr
ORDER BY
a.StackNbr
Current query results are:
StackNbr / UptimeHours / UptimePercentage / DowntimeHours / DowntimePercentage / Count
1 / 85.335 / 12.26 / 610.665 / 87.74 / 1077
2 / 13.457 / 1.93 / 682.543 / 98.07 / 185
3 / 9.998 / 1.44 / 686.002 / 98.56 / 137
4 / 89.121 / 12.8 / 606.879 / 87.2 / 1096
Current idletime query
SELECT
StackNbr,
(SUM(IdletimeMin)) / 60 IdletimeHours,
ROUND((SUM(IdletimeMin) / ((DATEDIFF(d, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60)) * 100, 2) IdletimePercentage,
COUNT(IdletimeMin) Count
FROM
IngStackerIdletime
WHERE
IdletimeMin > 0
AND DateTm BETWEEN DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)
AND DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)
GROUP BY
StackNbr
ORDER BY
StackNbr
Current query results
StackNbr / IdletimeHours/ IdletimePercentage /Count
1 / 112.531 / 16.17 / 1363
2 / 190.464 / 27.37 / 2278
3 / 195.588 / 28.1 / 2336
4 / 116.015 / 16.67 / 1403
As best I can tell from your question you just want to carry out a straight join between your 2 datasets, which you do by using them as sub-queries as shown below. I wasn't 100% sure on how you wanted to calculate "Total current monthly hours" so added a couple of options.
Personally I would highly recommend splitting out your date calculations so you only carry them out once, rather than repeating that complex logic again and again which not only makes the query hard to read, but means the potential for a mistake is massive.
SELECT X.*, Y.*
-- Calculation using total hours in the month
, (Y.IdletimeHours - ((DATEDIFF(day,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1))+1)*24)/X.UptimeHours) RuntimePercentage
-- Calculation using hours to date in the month
, (Y.IdletimeHours - ((DATEDIFF(day,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), CONVERT(date, GETDATE()))+1)*24)/X.UptimeHours) RuntimePercentage
FROM (
SELECT a.StackNbr
, (SUM(a.UptimeMin))/60 UptimeHours
, ROUND((SUM(a.UptimeMin) / ((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0),DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60))*100,2) UptimePercentage
, (((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0),DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60) - SUM(a.UptimeMin))/60 DowntimeHours
, ROUND((((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0),DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60) - SUM(a.UptimeMin)) / ((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0),DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60) * 100,2) DowntimePercentage
, COUNT(UptimeMin) [Count]
FROM IngStackerUptime a
WHERE a.UptimeMin > 0 AND a.DateTm BETWEEN DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) AND DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)
GROUP BY a.StackNbr
) X
INNER JOIN (
SELECT StackNbr
, (SUM(IdletimeMin)) / 60 IdletimeHours
, ROUND((SUM(IdletimeMin) / ((DATEDIFF(d, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)) * 24) * 60)) * 100, 2) IdletimePercentage
, COUNT(IdletimeMin) Count
FROM IngStackerIdletime
WHERE IdletimeMin > 0 AND DateTm BETWEEN DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0) AND DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1)
GROUP BY StackNbr
) Y on Y.StackNbr = X.StackNbr
ORDER BY X.StackNbr;
Here is some skeleton code for how you might extract out the date calculations to avoid repeating them:
SELECT X.*, Y.*
FROM (
VALUES (DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0), DATEADD(month, DATEDIFF(month, -1, GETDATE()), -1))
) D (StartDate, EndDate)
CROSS APPLY (
SELECT a.StackNbr
FROM IngStackerUptime a
WHERE a.UptimeMin > 0 AND a.DateTm BETWEEN D.StartDate AND D.EndDate
GROUP BY a.StackNbr
) X
CROSS APPLY (
SELECT StackNbr
FROM IngStackerIdletime
WHERE IdletimeMin > 0 AND DateTm BETWEEN D.StartDate AND D.EndDate
GROUP BY StackNbr
) Y
WHERE Y.StackNbr = X.StackNbr
ORDER BY X.StackNbr;
Note: Consistent layout, casing and formatting make a query much easier to read and manage.
Also, I'm not a fan of BETWEEN because it unintuitive what the boundaries are and it doesn't work if you accidentally end up with a time component in your datetime ranges. Date >= Startdate and Date < dateadd(day, 1, EndDate) is more obvious and reliable (or Date >= Startdate and Date < dateadd(month, 1, StartDate)).
SELECT a.StackNbr, (Sum(a.UptimeMin))/60 UptimeHours,
round((Sum(a.UptimeMin) / ((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, getDate()), 0),DATEADD(month, DATEDIFF(month, -1, getDate()), -1)) * 24) * 60))*100,2) UptimePercentage,
(((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, getDate()), 0),DATEADD(month, DATEDIFF(month, -1, getDate()), -1)) * 24) * 60) - Sum(a.UptimeMin))/60 DowntimeHours,
Round((((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, getDate()), 0),DATEADD(month, DATEDIFF(month, -1, getDate()), -1)) * 24) * 60) - sum(a.UptimeMin)) / ((DATEDIFF(d,DATEADD(month, DATEDIFF(month, 0, getDate()), 0),DATEADD(month, DATEDIFF(month, -1, getDate()), -1)) * 24) * 60) * 100,2) DowntimePercentage,
(Sum(b.IdletimeMin))/60 b.IdletimeHours, round((Sum(b.IdletimeMin) / ((DATEDIFF(d,DATEADD(b.month, DATEDIFF(b.month, 0, getDate()), 0),DATEADD(b.month, DATEDIFF(b.month, -1, getDate()), -1)) * 24) * 60))*100,2) b.IdletimePercentage,
Count (b.IdletimeMin) Count
Count (UptimeMin) Count
From IngStackerUptime a
,IngStackerIdletime b
Where a.UptimeMin > 0 and a.DateTm Between DATEADD(month, DATEDIFF(month, 0, getDate()), 0) and DATEADD(month, DATEDIFF(month, -1, getDate()), -1)
and a.stacknbr = b.stacknbr
and b.IdletimeMin > 0 and b.DateTm Between DATEADD(b.month, DATEDIFF(b.month, 0, getDate()), 0) and DATEADD(b.month, DATEDIFF(b.month, -1, getDate()), -1)
Group by a.StackNbr Order by a.StackNbr

Get every month of the current year in SQL Server

I'm using the following code to get the date of every day in the current week, in SQL Server:
SELECT
DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) Monday,
DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) + 1 Tuesday,
DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) + 2 Wednsday,
DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) + 3 Thursday,
DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) + 4 Friday,
DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) + 5 Saturday,
DATEADD(wk, DATEDIFF(wk, 0, GETDATE()), 0) + 6 Sunday;
I'm using this query to fill a bar chart in a asp.net application.
I need the same thing but with the months of the current year.
Can you help me with this, please?
Edit: More like a query to retrieve data from every month of this year.
This will return the first and last day of every month for the current year.
select FirstDay = dateadd(month, thisMonth - 1, dateadd(year, datediff(year, 0, getdate()), 0))
, LastDay = dateadd(day, -1, dateadd(month, thisMonth, dateadd(year, datediff(year, 0, getdate()), 0)))
from
(
values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12)
) x(thisMonth)

Using CASE in WHERE clause?

I am getting the following error in my WHERE clause on the very last AND statement AND CAST(cp.EndDate...). I just added the CASE statement to know if the month is January and to compare the cp.startdate >= value1 OR value 2
Error:
An expression of non-boolean type specified in a context where a condition is expected, near 'and'.
My WHERE clause:
WHERE
(CAST(cp.startdate AS DATE) >= CAST(DATEADD(year, -1, DATEADD(month, DATEDIFF(month, 0, getdate()), 0)) AS DATE)
OR --FirstDayOfCurrentMonthPriorYear
CASE
WHEN DATEPART(month,getdate()) = 1 --month is January
THEN CAST(DATEADD(month, DATEDIFF(month, 0, getdate())-1, 0) AS DATE) --FirstDayOfLastMonthPriorYear
ELSE CAST(DATEADD(year, -1, DATEADD(month, DATEDIFF(month, 0, getdate()) -1, 0)) AS DATE) --FirstDayOfLastMonthPriorYear
END)
AND CAST(cp.EndDate AS DATE) <= CAST(DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE()) + 1, 0)) AS DATE) --LastDayOfCurrentMonthCurrentYear
Not sure what's wrong... any help in implementing this would be appreciated.
From a pure syntax point of view, you need to compare something to your CASE output. Something like this would be syntactically correct.
WHERE
(
CAST(cp.startdate AS DATE) >= CAST(DATEADD(year, -1, DATEADD(month, DATEDIFF(month, 0, getdate()), 0)) AS DATE)
OR
CAST(cp.startdate AS DATE) >= CASE
WHEN DATEPART(month,getdate()) = 1 --month is January
THEN CAST(DATEADD(month, DATEDIFF(month, 0, getdate())-1, 0) AS DATE)
ELSE CAST(DATEADD(year, -1, DATEADD(month, DATEDIFF(month, 0, getdate()) -1, 0)) AS DATE)
END
)
AND CAST(cp.EndDate AS DATE) <= CAST(DATEADD(day, -1, DATEADD(month, DATEDIFF(month, 0, GETDATE()) + 1, 0)) AS DATE)
Here is the previous question
I think this is what you are looking for:
WHERE CAST(cp.startdate AS DATE) >= CASE WHEN DATEPART(MONTH,GETDATE()) = 1
THEN DATEADD(DAY,1,EOMONTH(GETDATE(),-1))
ELSE DATEADD(YEAR,-1,DATEADD(DAY,1,EOMONTH(GETDATE(),-1)))
END --FirstDayOfCurrentMonthPriorYear
AND CAST(cp.EndDate AS DATE) <= EOMONTH(GETDATE()) --LastDayOfCurrentMonthCurrentYear
This checks that the cp.startdate is greater than or equal to the first day of the current month in the prior year, and that the cp.enddate is less than or equal to the last day of the current month. Replace GETDATE() with your date of choice.

Week of the Month in SQL

DECLARE #date DATETIME= GETDATE()
SELECT DATEDIFF(WEEK,
DATEADD(WEEK,
DATEDIFF(WEEK, 0,
DATEADD(MONTH, DATEDIFF(MONTH, 0, #date), 0)),
0), #date - 1) + 1
What is purpose of 0 as a parameter in the datediff() function?
The specific answer to your question is that the 0 is just a way to get the beginning of the month:
dateadd(month, datediff(month, 0, #date), 0)
This is one method to do this in SQL Server, because it does not offer a "date truncate" function. I prefer:
dateadd(day, 1 - day(#date), #date)
(Although admittedly this is a wee bit more complicated if #date has a time component.)
However, a much simpler way to do this is:
select (day(#date) - 1) / 7) as week_of_month
Below gets the number of months from a reference point
datediff(month, 0, #date)
Then it is used to add to the reference date back to reach the first day of the month
dateadd(month,
datediff(month, 0, #date),
0)
So it is used to find the first day of the current month
declare #date datetime = getdate()
select
getdate(),
datediff(month, 0, #date),
dateadd(month,
datediff(month, 0, #date),
0)

GETDATE last month

I am trying to list last a website's statistics.
I listed Last 30 days with;
CONVERT(VARCHAR(10), S.DATEENTERED, 101)
BETWEEN
CONVERT(VARCHAR(10), GETDATE()-30, 101)
AND
CONVERT(VARCHAR(10), GETDATE(), 101)
and this month with;
RIGHT(CONVERT(VARCHAR(10), S.DATEENTERED, 103), 7) =
RIGHT(CONVERT(VARCHAR(10), GETDATE(), 103), 7)
but I have no idea what query to use for last month. I tried with;
RIGHT(CONVERT(VARCHAR(10), S.DATEENTERED, 103), 7) =
RIGHT(CONVERT(VARCHAR(10), GETDATE()-1, 103), 7)
Did not work.
Dates are always a joy to work with in any programming language, SQL not excluded.
To answer your question to find all records that occurred last month
select S.DATEENTERED
,*
from sometable S
where S.DATEENTERED
between dateadd(mm, datediff(mm, 0, dateadd(MM, -1, getdate())), 0)
and dateadd(ms, -3, dateadd(mm, datediff(mm, 0, dateadd(MM, -1, getdate())) + 1, 0))
order by 1
To expand the best means for getting records within a certain time-frame is by utilizing the datediff function, dateadd function, and the between condition in the where clause.
select 'howdy'
,getdate()
where getdate()
between dateadd(mm, 0, 0)
and dateadd(ms, -3, dateadd(mm, datediff(mm, 0, dateadd(mm,-1,getutcdate())) + 1, 0))
The above code will result in no records returned because it is checking to see if today's date is between 1900-01-01 00:00:00.000 and the last possible recorded date of last month (the last day and 23:59:59.997 - SQL Server DATETIME columns have at most a 3 millisecond resolution).
The following code will return a record as the date we are searching for is one month ago.
select 'howdy'
,dateadd(mm, -1, getdate())
where dateadd(mm, -1, getdate())
between dateadd(mm, 0, 0)
and dateadd(ms, -3, dateadd(mm, datediff(mm, 0, dateadd(mm,-1,getutcdate())) + 1, 0))
A break down of the where clause:
WHERE getdate() -- date to check
between dateadd(mm, 0, 0) -- begin date
and dateadd(ms, -3, dateadd(mm, datediff(mm, 0, dateadd(mm,-1,getutcdate())) + 1, 0)) -- end date
Finally, a variety of dates can be ascertained in this manner here is a pretty complete list:
select dateadd(mm, 0, 0) as BeginningOfTime
,dateadd(dd, datediff(dd, 0, getdate()), 0) as Today
,dateadd(wk, datediff(wk, 0, getdate()), 0) as ThisWeekStart
,dateadd(mm, datediff(mm, 0, getdate()), 0) as ThisMonthStart
,dateadd(qq, datediff(qq, 0, getdate()), 0) as ThisQuarterStart
,dateadd(yy, datediff(yy, 0, getdate()), 0) as ThisYearStart
,dateadd(dd, datediff(dd, 0, getdate()) + 1, 0) as Tomorrow
,dateadd(wk, datediff(wk, 0, getdate()) + 1, 0) as NextWeekStart
,dateadd(mm, datediff(mm, 0, getdate()) + 1, 0) as NextMonthStart
,dateadd(qq, datediff(qq, 0, getdate()) + 1, 0) as NextQuarterStart
,dateadd(yy, datediff(yy, 0, getdate()) + 1, 0) as NextYearStart
,dateadd(ms, -3, dateadd(dd, datediff(dd, 0, getdate()) + 1, 0)) as TodayEnd
,dateadd(ms, -3, dateadd(wk, datediff(wk, 0, getdate()) + 1, 0)) as ThisWeekEnd
,dateadd(ms, -3, dateadd(mm, datediff(mm, 0, getdate()) + 1, 0)) as ThisMonthEnd
,dateadd(ms, -3, dateadd(qq, datediff(qq, 0, getdate()) + 1, 0)) as ThisQuarterEnd
,dateadd(ms, -3, dateadd(yy, datediff(yy, 0, getdate()) + 1, 0)) as ThisYearEnd
Using the above list a range of any type can be determined.
The following will find you the start of the last month:
-- Start of last month
SELECT CAST('01 '+ RIGHT(CONVERT(CHAR(11),DATEADD(MONTH,-1,GETDATE()),113),8) AS datetime)
You would then find the start of this month, using the following, minus one.
-- Start of the month
SELECT CAST('01 '+ RIGHT(CONVERT(CHAR(11),GETDATE(),113),8) AS datetime)
When I have to work with dates in SQL Server I often reference Robyn Page's SQL Server DATE/TIME Workbench. The workbench (tutorial) is well laid out and contains just about everything I have ever needed when working with dates on SQL Server.
How about this?
select DATEADD(month, -1, GETDATE())
I would suggest using the first day of last month and the first day of the current month for the operation and rather than using BETWEEN use >= and <. That's my personal opinion, but I believe you will find there are performance and maintainability benefits to this approach.
Here's the sql. You will notice I've included the last day of the last month value just in case you end up going with another approach.
Keep in mind, these dates are based off of 12:00AM that day. In other words, getting values between 6/1/2009 and 6/30/2009 won't get you what you want as all of 6/30/2009 is excluded. If you use the first day of July (7/1/2009) you are covered.
Again, I recommend avoiding BETWEEN all together as shown below. Best of luck.
Declare #LastMonthFirstDay datetime
Declare #LastMonthLastDay datetime
Declare #ThisMonthFirstDay datetime
Set #LastMonthFirstDay = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP) - 1, 0);
Set #ThisMonthFirstDay = DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0);
Set #LastMonthLastDay = DATEADD(DAY, -1, DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0));
Select * From Table
Where DateEntered >= #LastMonthFirstDay
And DateEntered < #ThisMonthFirstDay;
Try using the DATEADD function. You can add a -1 with the MONTH (mm) datepart and it should work. Here is a link
where year(S.DATEENTERED) = year(dateadd(mm, -1, getdate())) and month(S.DATEENTERED) = month(dateadd(mm, -1, getdate()))
Might not be good performance-wise but you've got the idea.
GET FIRST DAY OF LAST MONTH
SELECT DATEADD(MM, DATEDIFF(MM, '01/01/2000', DATEADD(MM, -1,GETDATE())), '01/01/2000')
GET LAST DAY OF LAST MONTH
SELECT DATEADD(SS,-1,DATEADD(MM, DATEDIFF(MM,'01/01/2000',GETDATE()),'01/01/2000'))
Then search based on this range.
Try:
declare #lastm int
set #lastm = datepart(mm,getdate()) - 1
...
where datepart(mm,s.dateentered) = #lastm