MS Access SQL query for testing dates for last day of the quarter - sql

OK, so I have a load of records in a table and they have many different dates.
I want to retern only those records whose date falls on the last day of whatever quarter it's in.
I.e. I basically need the equivalent of a lastDayOfQuarter(date) function that calculates the date that is the last day in the quarter for the date passed to it.
e.g. lastDayOfQuarter(#16/05/2013#) = #30/06/2013#
My query might look like:
SELECT * FROM mytable
WHERE mytable.rdate = lastDayOfQuarter(mytable.rdate);
This query will be run over PDO so no VBA allowed. Native MS Access only.
I would also prefer to not use string manipulation as there is a difference between US and EU dates which might cause issues down the line.

I'm answering myself as, with the help of HansUp answering a previous question of mine for finding month-end records, I found out quite an easy way to acheive this:
WHERE DateValue(m.rdate) = DateSerial(Year(m.rdate), Month(m.rdate) + 1, 0)
AND Month(m.rdate) IN(3,6,9,12)

the "last day of the quarter" could be different for different users. You may be best to build a table of "lastdays" based on your business rules, then use that table in your query.

And here as short answer...Try
Select DateAdd(day, -1, dateadd(qq, DATEDIFF(qq, 0, 'year-month-day'), 0))
For today it should give you
2013-06-30 00:00:00.000
SO for your Table you should use :
SELECT * FROM mytable
WHERE mytable.rdate = DateAdd(day, -1, dateadd(qq, DATEDIFF(qq, 0, mytable.rdate), 0));

Related

T-SQL: How to get all records prior to the first day of the current month?

Using SQL Server: I am trying to find all records prior to the first day of the current month and set this as a parameter in an SSRS report (so I can't use a static value).
So, I need all records prior to the first day of the each current month going forward in column CREATEDDATETIME ('yyyy-mm-dd').
I have seen a lot of threads on how to find records for a specific month and various other searches but none specifically related to the above. Interested to see if the EOMONTH function will be of use here.
Thanks for the help and advice.
Here is an expression to use EOMONTH() function with optional parameter -1.
Explanations:
DateAdd: add 1 day to expression
getdate is current date
EOMONTH is end day of a given month; however, if you put an optional integer -1, this would mean last month
Thus: first day of current month is add one day to end of day last month
SELECT DATEADD(DAY,1,EOMONTH(getdate(),-1));
Result: 2018-04-01
SO in your query:
select *
from table
where CREATEDDATETIME < DATEADD(DAY,1,EOMONTH(getdate(),-1));
I would use datefromparts():
select t.*
from t
where CREATEDDATETIME < datefromparts(year(getdate()), month(getdate()), 1);
There's already two other answers that work, but for completeness here is a third common technique:
SELECT *
FROM [table]
WHERE CREATEDDATETIME < dateadd(month, datediff(month,0, current_timestamp), 0)
You might also get answers suggesting you build the date using strings. Don't do that. It's both the least efficient and most error prone option you could use.
all three answers are great, how ever you may find that it will select all the data prior to the 1st day of the current month until the 1st Createdate. This could cause the report to take forever to run, Maybe building in a limitation to the code I would use something like this to build a report that gives details for last month only.
Select [columns]
from [source]
where [Createdate] between
/*First day of last Month*/
DATEADD(mm, DATEDIFF(mm, 0, Getdate())-1, 0 and
/*First day of this Month*/
dateadd(mm,datediff(mm,0,Getdate()),0)

How to handle Dates correctly in SSMS

Came across this issue in our scripts since the New year.
We have several scripts which look back 1 month from current UTC date.
Since the New Year, these scripts return zero results because, I assume, Sql doesn't see month 12 as being minus 1 from month 1.
Is there a way to force sql to see the year as the rotating data it is rather than an incremental line?
**Edit
Apologies, I forgot to add examples.
So, one line reads
Select .... Where ...
And month (timevalue) = month (getutcdate ()) -1
This gives zero results despite working correctly until January.
I've changed it temporarily to be = 12 which does return the correct data.
**Edit 2
Yep, thanks for the link and sample code. Works perfectly so far. I guess with our current setup it's not using daytime as I assumed, but instead using the month value as an int?
Check below, I hope it will help:
SELECT MONTH(DATEADD(MONTH, -1, GETUTCDATE())) AS PreviousMonth
returns:
PreviousMonth
12
So your query should be:
Select .... Where ... And month (timevalue) = MONTH(DATEADD(MONTH, -1, GETUTCDATE()))

SQL Query Subtract 1 month

I need to query SQL for data that falls into a last month date. I thought I was using the correct query logic but I get no results and I know there are results. The snippet of code is this:
MONTH(n.JOIN_DATE) = DATEADD(month, - 1, GETDATE())
This is giving me no results and I need to get anyone who has a join date of last month. What am I missing?
Use this:
MONTH(n.JOIN_DATE) = MONTH(DATEADD(month, - 1, GETDATE()))
You need to compare apples with apples, so compare the numerical month on both sides of the equation.
Massive credit to #PaulL for figuring this out before I did.
Update:
As #DasBlinkenLight and Matt pointed out, just comparing by month leaves the door open for multiple years to be returned. One possible fix would be to also compare the years, e.g.
WHERE MONTH(n.JOIN_DATE) = MONTH(DATEADD(month, - 1, GETDATE())) AND
YEAR(n.JOIN_DATE) = YEAR(DATEADD(month, - 1, GETDATE()))
MONTH(...) produces a month number. You should not compare it to the result returned by DATEADD, which is actually a date.
If you are looking for everyone who has joined less than a month ago, you can do it like this:
WHERE DATEADD(month, 1, n.JOIN_DATE) > GETDATE()
This takes into account the year and the day as well, not only the month.
If you are looking for everyone who joined last month, no matter on what day, you can use a more complex condition:
WHERE MONTH(DATEADD(month, -1, GETDATE()) = MONTH(n.JOIN_DATE)
AND YEAR (DATEADD(month, -1, GETDATE()) = YEAR (n.JOIN_DATE)
The second condition is necessary to avoid confusion between members joining last month and members joining on the same month one or more years ago.
MONTH(n.JOIN_DATE) returns a numeric which indicate the month in date m.JOIN_DATE
DATEADD(month, - 1, GETDATE()) returns a date which indicate date in last month.
So, you can use this instead :
MONTH(n.JOIN_DATE)= MONTH(DATEADD(month, - 1, GETDATE()))
OR
n.JOIN_DATE = DATEADD(month, - 1, GETDATE())
MONTH(n.JOIN_DATE) will only return the numerical value of the month (e.g.: 11 or 5).
DATEADD(MONTH, -1, GETDATE()) will simply subtract one month from the current date. It is still in a DATETIME format.
You may be looking for:
MONTH(n.JOIN_DATE) = MONTH(DATEADD(MONTH, -1, GETDATE()))
SELECT
DATEFROMPARTS(YEAR(DATEADD(month,-1,GETDATE())),MONTH(DATEADD(month,-1,GETDATE())),1) AS StartOfLastMonth
,DATEADD(day,-1,(DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()),1))) AS EndOfLastMonthAsDate
,DATEADD(day,-3,CAST(DATEFROMPARTS(YEAR(GETDATE()),MONTH(GETDATE()),1) AS DATETIME)) AS EndOfLastMonthMidngith
,CAST(DATEADD(month,-1,GETDATE()) AS DATE) AS OneMonthAgoStrartOfDay
,CAST(GETDATE() AS DATE) AS StartOfToday
,DATEADD(MS,-3,CAST(CAST(GETDATE() AS DATE) AS DATETIME)) AS MidnightLastNight
Okay As people have definitely illustrated there are a lot of different answers to your question and all are built upon similar premise. using DATEADD() with a negative number to go back a month. Or to compare month and year to see if they are the same. The former being geared at 1 month ago to today and the later being last month.
All of the answers so far, expect #DasBlinkenLight and #TimBiegeleisen, fail to take into account TIME component of your column and the GETDATE() function if you have one. If your column is DATETIME you will need to take that into account. The above SELECT query that will arm you with some ways of getting to different dates that i suspect will meet your needs.
As far as using BETWEEN with dates be careful! because the values you put in are inclusive so if you put GETDATE() on the right side of the between statement you will get today's results too but you might really want UP TO to today in which case you should change your right side argument. Also I am not sure about Oracle, mysql, etc. but Micrsofot SQL-Server is accurate to .003 milliseconds. So if you really want to look at midnight of a date you should look at 23:59:59.997 because .998 and .999 will round up to the next day.
Also to further simplify if you don't want time components you can also cast your column to DATE and it essentially drops off the time and the BETWEEN because a little clearer too, e.g. CAST(n.JOIN_DATE AS DATE)
There are definitely other questions on this subject on stackoverflow I encourage you to research.
I knew this was a simple one and I was missing something to it. My code was wrong based upon the many responses I received on this and I was comparing apples to oranges and not apples to apples. Once I added the Month() around the dateadd function, it worked.
The reply to this answer are correct. But in the light of best practice writing your query this way will make it less SARGABLE, hence making it ignore indexes if you have one. It might be better to write it as
WHERE n.JOIN_DATE between DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE())-1, 0) AND DATEADD(MONTH, DATEDIFF(MONTH, -1, GETDATE())-1, -1)
based on the comment below I have modified the query. I guess I did not read the question in depth.

SQL Query for retreiving records that fall on the last day of the month

I have a table with records from many dates.
I would like to perform a query that only returns records that fall on the last day of the date's month. Something like:
SELECT * FROM mytable
WHERE DATEPART(d, mytable.rdate) = DATEPART(d,DATEADD(m,1,DATEADD(d, -1, mytable.rdate)))
Except this doesn't work as the rdate in the right-hand side of the argument should be the last day of it's month for the dateadd to return the correct comparison.
Basically is there an concise way to do this comparison?
An equivalent for quarter-ends would also be very helpful, but no doubt more complex.
EDIT:
Essentially I want to check if a given date is the last in whatever month (or quarter) it falls into. If it is, return that record. This would involve a some function to return the last day of the month of any date. e.g. lastdayofmonth('2013-06-10') = 30 (so this record would not be returned.
EDIT2:
For the case of returning the records that fall on the last day of the quarter they are in it would need to be something like:
SELECT * FROM mytable
WHERE DATEPART('d', mytable.rdate) = lastdayofmonth(mytable.rdate)
AND DATEPART('m', mytable.rdate) = lastmonthofquarter(mytable.rdate);
The tricky bit is the lastdayofmonth() and lastmonthofquarter() functions
Use the DateSerial Function to compute the last day of the month for a given date.
Passing zero as the third argument, day, actually returns the last date of the previous month.
rdate = #2013-7-24#
? DateSerial(Year(rdate), Month(rdate), 0)
6/30/2013
So to get the last date from the rdate month, add 1 to the month argument.
? DateSerial(Year(rdate), Month(rdate) + 1, 0)
7/31/2013
You might suspect that approach would break for a December rdate, since Month() + 1 would return 13. However, DateSerial still copes with it.
rdate = #2013-12-1#
? DateSerial(Year(rdate), Month(rdate) + 1, 0)
12/31/2013
If you will be running your query from within an Access application session, you can build a VBA function based on that approach, and use the custom function in the query.
However, if the query will be run from an ODBC or OleDb connection to the Access db, the query can not use a VBA user-defined function. In that situation, you can use DateSerial directly in your query.
SELECT m.*
FROM mytable AS m
WHERE m.rdate = DateSerial(Year(m.rdate), Month(m.rdate) + 1, 0)
That should work if your rdate values all include midnight as the time component. If those values include other times, use DateValue.
WHERE DateValue(m.rdate) = DateSerial(Year(m.rdate), Month(m.rdate) + 1, 0)
Try This.
SELECT * FROM mytable
WHERE DATEPART(d, mytable.rdate) =
DATEADD(d, -1, DATEADD(m, DATEDIFF(m, 0, GETDATE()) + 1, 0))
Try this one, this is tested on MS Access:
Using String Concatenation:
SELECT * FROM mytable
WHERE
DatePart('d',mytable.rdate) =
DatePart('d',dateadd('m',1, "1/" & DatePart('m',mytable.rdate) & "/" & DatePart('yyyy',mytable.rdate))-1);
Update without using string concatenation:
SELECT * FROM
(SELECT *,
DATEPART('d',DATEDIFF('m',0,mytable.rdate)+1,
DATEADD('m',1,
DATEADD('d',DATEDIFF('d',0,mytable.rdate)- DATEPART('d',mytable.rdate)+1,0))-1) as EOMonth
FROM mytable ) A
WHERE DATEPART('d',mytable.rdate) = DATEPART('d',EOMonth)

What is the simplest and most efficient way to get the first and last date of the previous month?

I'm trying to get the first and last day of the previous month. What I really need is a range for a BETWEEN clause, so I need the first second of the first day, and the last second of the last day.
This is the code I've been using:
set #startDate = DATEADD(mm, DATEDIFF(mm,0,DATEADD(mm, -1, getdate())), 0)
set #endDate = dateadd(ms,-3,DATEADD(mm, DATEDIFF(mm,0,getdate() ), 0))
However, for today, this is actually returning 4/1/2011 and 5/1/2011, which is not completely accurate. I want to get the last second of 4/30/2011 for the endDate.
I've been googling and I see many different ways to get the first/last day of a month. Even on SO itself, I see many different variations of this question with many different answers. I'd like to compile a list of all the methods to achieve this, and then determine which is the "best" (based on simplicity and efficiency)
(I should add that I'm using sql server 2000)
EDIT:
Re the enddate bug - this code is actually correct, the problem was just that #endDate was a smalldatetime. I changed it to a datetime and this is now working correctly
For dates I strongly recommend not using BETWEEN. This is highlighted by your need to remove 3ms from a date to get "the last moment of the previous day".
With continuous values (rather than discrete values), that can have varying degrees of accuracy, it is generally better to use >= AND <. For example...
WHERE myDateField >= '2012-04-01' AND myDateField < '2012-05-01'
By doing this you never need to even think about the accuracy of the myDateField data or data-type. It just works. Always.
With that in mind, your code is very close to what I would use...
SET #start = DATEADD(month, DATEDIFF(month, 0, getDate()) - 1, 0)
SET #end = DATEADD(month, DATEDIFF(month, 0, getDate()) , 0)
EDIT: as per the explanation from #Dems (please see the comments)
I think now my answer will be same as #Dems to we both are have same answers. :) #Dems Credit goes to you.
try this query it will get you the proper dates as per your need.
select DATEADD(mm, DATEDIFF(mm,0,DATEADD(mm, -1, GETDATE())), 0)
select DATEADD(mm, DATEDIFF(mm,0,GETDATE() ), 0)
and using this date you can directly use the >= and < as per the suggestion by #Dems below.