How to filter my results so it shows the last four months of data - sql - sql

I'm trying to create a stored procedure that gets the last 4 months worth of results from the below query but I'm unsure how to do this.
This is what I have done so far:
Declare #Number varchar(30) = '12'
Select
month = month(EndDate),
YEAR = YEAR(EndDate),
SUM(DownloadUnits) as downloads,
SUM(UploadUnits) as uploads,
number
from testTable
where number=#Number
GROUP BY MONTH(EndDate), Year(Enddate),number
How can I filter it out so that when I pass month parameter (I haven't created it yet) it filters out the results so it only shows the last four months? (I have hard coded the number parameter for testing)

The last N months from now meet the condition
where EndDate >= dateadd(month, -#DEDUCT_MONTHS, cast(getdate() as DATE))
Removing the cast will enforce the current time as a constraint as opposed to midnight N months ago.

If you need to get whole months then you will need to get the first of the month 4 months ago.
You can get the first of the current month using:
SELECT DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101');
Adapting this slightly will give you the first of the month 4 months ago:
SELECT DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()) - 4, '19000101');
Then you can just apply this filter to your query:
WHERE EndDate >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()) - 4, '19000101')
Or if you need to pass the number of months a parameter (it should be an INT not a varchar by the way):
WHERE EndDate >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()) - #Number, '19000101')
If you pass a date parameter, just replace GETDATE() with your parameter name.

DECLARE #StartDate date
SET #StartDate=Dateadd(Month, Datediff(Month, 0, DATEADD(m, -6, getdate())), 0)
--first day of the month, (current month-6 month)
The script above will return with the first day of the month - 6 month ago .
This solution is from stackoverflow somewhere, unfortunately I dont seem to find the original post.. :(
To understand how it works try to reverse-engineer as per follows:
DECLARE #StartDate1 date
SET #StartDate1= DATEADD(m, -6, getdate())
PRINT #Startdate1
DECLARE #StartDate2 int
SET #StartDate2= Datediff(Month, 0, DATEADD(m, -6, getdate()))
PRINT #Startdate2
DECLARE #StartDate3 date
SET #StartDate3=Dateadd(Month, 1369, 0)
PRINT #Startdate3

Related

How to pull the past two years of data, but not the data in the current month in SQL

I am trying to pull the data from the past two years, starting from the the past month (not taking into account the current month).
So it will pull all 2 years of data starting from 09/30/2021.
I've tried the following, but the months after September for 2020 get taken out:
WHERE YEAR(ACCDAT_0) >= (YEAR(GETDATE()) -2) AND MONTH(ACCDAT_0) < MONTH(dateadd(dd, -1, GetDate()))
DECLARE #d date = GETDATE();
SET #d = DATEFROMPARTS(YEAR(#d), MONTH(#d), 1);
SELECT ... WHERE ACCDAT_0 >= DATEADD(YEAR, -2, #d)
AND ACCDAT_0 < #d;
Several helpful date articles here, including why you want range queries and not things like YEAR(column): Dating Responsibly
You may try the following logic:
SELECT *
FROM yourTable
WHERE ACCDAT_0 >= DATEADD(year, -2, DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0)) AND
ACCDAT_0 < DATEADD(month, DATEDIFF(month, 0, GETDATE()), 0);

Pull records from previous three months

I want to pull back all the rows that have a report date from the previous 3 months. So If I'm running the code in March 2015, I want to pull back data from Dec14, Jan15, Feb 15.
I've tried to use the following but not had much success
Select * from table
where DATEPART(month, ReportDate) between Month(DATEADD(month, -1,GETDATE())) and Month(DATEADD(month, -3,GETDATE()))
You can get the first day of the current month using:
SELECT DATEADD(MONTH, DATEDIFF(MONTH, '1900001', GETDATE()), '19000101')
This basically just gets the number of months between now, and a fixed date, then adds this number of months back to the same fixed date, to get the first of the current month. Then it is just a case of adding this into your query, so your pseudo code is:
WHERE ReportDate < [start of this month]
AND ReportDate >= [start of 4 months ago]
And your actual code is:
WHERE ReportDate < DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101')
AND ReportDate >= DATEADD(MONTH, DATEDIFF(MONTH, '19000401', GETDATE()), '19000101');
Note that I have removed the function from the ReportDate column which will make your predicate sargable
Here are a couple of good articles on querying date ranges:
Bad habits to kick : mis-handling date / range queries
What do BETWEEN and the devil have in common?
You can try something like this,
create table Test(id int, TranDate datetime)
insert into Test (id, TranDate) values
(1, '2014-12-12'),
(2, '2014-11-10'),
(3, '2015-04-01'),
(4, '2015-02-02'),
(5, '2015-01-01')
declare #FromDate DateTime = dateadd(month, -4, getdate())
declare #ToDate DateTime = dateadd(month, -1, getdate())
select * from Test where TranDate >= #FromDate and TranDate <= #ToDate
Sql Fiddle Demo
Dont use BETWEEN clause in sql.
Try this:
SELECT *
FROM YourTableName
WHERE ReportDate
BETWEEN DATEADD(month, -4,GETDATE()) AND
DATEADD(month, -1,GETDATE())

Between Dates Where Clause With Shifting Date

Is it possible to do the following in SQL. I would like to write a code that will return records between certain dates, but will automatically update when the report runs. So for example:
on 12/18 I would like to return records from 11-1 to 11/18 and 12/1 to 12/18 so I can compare month over month on these records in my report.
I understand that I can do:
WHERE
[database] BETWEEN '2013-11-01' and DATEADD(Month, 1, getdate ()))
and not [database] IN ('2013-11-19 and '2013-11-30')
but I will have to go into the query everyday to update the not between. I would like to make it so that I can run the query on any day and get the records from the previous month up until the date match for this month. I currently have been working with this:
B.[datepaid] between DATEADD(Month, -1, getdate() )
and DATEADD(MONTH, 1, getdate() ))
but it is returning all records from November.
I would recommend against using BETWEEN with Dates as it can have some unexpected results. But in your case you can use:
WHERE ([Date] >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()) - 1, '19000101')
AND [Date] < DATEADD(MONTH, -1, GETDATE()))
OR ([Date] >= DATEADD(MONTH, DATEDIFF(MONTH, '19000101', GETDATE()), '19000101')
AND [Date] < GETDATE());
Demo on SQL Fiddle

How to query 2 different date ranges depending on the day it is run

I am making a program that auto-runs using windows scheduler. What I'd like to do is set the program to run on the 1st and the 16th of every month. If the program run's on the 1st. I'd like to have the query run for last month... For example if today was the first of august I would want it to run 7/1/12 - 7/31/12. If I run the program on the 16th I want it to run the query for the current month to the 15th. For example if it were 8/16, I would want the program to run the query for 8/1/12 - 8/15/12. What is the best way to accomplish this? Do I go with 2 seperate programs with the query attaching it to the correct date range? One scheduled to run on the first of every month, and one on the 16th? How would I go about getting the date range and the year as it will depend on which month/year it is run... My query is:
SELECT Store_Number, Invoice_Number, Invoice_Date, Extended_Price, Warranty_Amount, Quantity_Sold, Invoice_Detail_Code
FROM Invoice_Detail_Tb
WHERE (Warranty_Amount > 0) AND (Invoice_Date BETWEEN CONVERT(DATETIME, '2012-08-01 00:00:00', 102) AND CONVERT(DATETIME, '2012-08-05 00:00:00', 102))
ORDER BY Store_Number, Invoice_Date
Try 8/1/2012 and 8/16/2012 as the date. It returns the values you want to see:
declare #date datetime = '8/16/2012', #start datetime, #end datetime
if datepart(dd, #date) = 1
begin
set #start = dateadd(mm, -1, #date)
set #end = dateadd(dd, -1, #date)
end
else
begin
set #start = dateadd(dd, -15, #date)
set #end = dateadd(dd, -1, #date)
end
select #start, #end
It would be fairly easy to adapt this so that it would dynamically calculate the correct start and end dates based on any input date -- so you could run it anytime during the month.
This should be simple, let me throw some examples for you.
I truly think this should be one scheduled task, not multiple ones.
It is easier at the end of the day to point and look at one scheduled task (one procedure)
then go digging up multiple procedures just to see what might have wen't wrong.
The task can be scheduled using the SQL Server Agent (under the jobs section). The job can point to one single stored procedure.
In the procedure you can do a simple if else if logic.
IF DAY(GetDate()) = 1
--code here
ELSE IF DAY(GETDATE()) = 16
--code here
DAY(date_expression) returns the day in a datetime column. Ironically there is a MONTH and YEAR function if you for some reason need those. The rest is simple, if you are on the first date of the month then perform the monthly query from months first date till next months first day - 1, this becomes:
SELECT DATEADD(s,-1,DATEADD(mm, DATEDIFF(m,0,GETDATE())+1,0))
Otherwise if it hits on the 16th, you can run on the first day until half of the month.
If you have your query in a view, you might use this:
where
Invoice_Date between
(
case
when datepart(dd, getdate()) = 1 then dateadd(mm, -1, getdate())
else dateadd(dd, -15, getdate())
end
)
and
(
case
when datepart(dd, getdate()) = 1 then dateadd(dd, -1, getdate())
else dateadd(dd, -1, getdate())
end
)
UPDATE: Ignoring the time
(I know it looks ugly.)
where
Invoice_Date between
(
case
when datepart(dd, dateadd(dd, datediff(dd, 0, getdate()), 0)) = 1 then dateadd(mm, -1, dateadd(dd, datediff(dd, 0, getdate()), 0))
else dateadd(dd, -15, dateadd(dd, datediff(dd, 0, getdate()), 0))
end
)
and
(
case
when datepart(dd, dateadd(dd, datediff(dd, 0, getdate()), 0)) = 1 then dateadd(dd, -1, dateadd(dd, datediff(dd, 0, getdate()), 0))
else dateadd(dd, -1, dateadd(dd, datediff(dd, 0, getdate()), 0))
end
)
This is how I usually do something like that. Your stored procedure should look something like this:
declare
#today datetime ,
#dtFrom datetime ,
#dtThru datetime
------------------------------------------------------
-- get the current date, discarding the time component
------------------------------------------------------
set #today = convert(datetime,convert(varchar,current_timestamp,112),112) -- get todays date, discarding the time component
---------------------------------------------------------------------------------------------------------------------------------------------------
-- determine the start/end dates of the query period.
--
-- if the query date (#today) is in the 1st half of the month (1st - 15th), the query range is the entire preceding month
-- if the query date (#today) is in the last half of the month (16 - 31st), the query range is the 1st of the current month up to the current date
---------------------------------------------------------------------------------------------------------------------------------------------------
if ( datepart(day) < 16 )
begin
set #dtThru = dateadd(day, - datepart(day, #today ) , #today ) -- set the end date to the last day of the previous month
set #dtFrom = dateadd(day, 1 - datepart(day, #dtThru ) , #dtThru ) -- set the start date to the first day of the previous month
end
else
begin
set #dtfrom = dateadd(day, 1 - datepart(day, #today) , #today ) -- set the start date to the first day of the current month
set #dtThru = #today
end
----------------------------------------------------------------------------------------------------------------------
-- finally, adjust the start/end times to cover the entire gamut of date/time values for the month
--
-- We don't have to modify #dtFrom at all: we know its time component is 00:00:00.000 already. However, we want
-- #dtThru to have a time component of 23:59:59.997, due to SQL Server's broken way of counting time -- any time value
-- higher than that (e.g., '23:59.59.999') is 'rounded up' to start-of-day (00:00.00.000), the next day. Brilliant!
--
----------------------------------------------------------------------------------------------------------------------
set #dtThru = dateadd(ms, -3 , dateadd(day,1,#dtThru) )
--------------------------------
-- return the data to the caller
--------------------------------
SELECT Store_Number ,
Invoice_Number ,
Invoice_Date ,
Extended_Price ,
Warranty_Amount ,
Quantity_Sold ,
Invoice_Detail_Code
FROM Invoice_Detail_Tb id
WHERE Warranty_Amount > 0
AND Invoice_Date BETWEEN #dtFrom AND #dtThru
ORDER BY Store_Number ,
Invoice_Date
If you aren't using a stored procedure, you can accomplish the same thing with a parameterized query. Compute the two DateTime values needed. Put placeholders in your select statement ('#dtFrom' and '#dtThru'). When you execute the query, pass in your two DateTime values as SqlParameter objects with names matching the placeholders.

Get the records of last month in SQL server

I want to get the records of last month based on my db table [member] field "date_created".
What's the sql to do this?
For clarification,
last month - 1/8/2009 to 31/8/2009
If today is 3/1/2010, I'll need to get the records of 1/12/2009 to 31/12/2009.
All the existing (working) answers have one of two problems:
They will ignore indices on the column being searched
The will (potentially) select data that is not intended, silently corrupting your results.
1. Ignored Indices:
For the most part, when a column being searched has a function called on it (including implicitly, like for CAST), the optimizer must ignore indices on the column and search through every record. Here's a quick example:
We're dealing with timestamps, and most RDBMSs tend to store this information as an increasing value of some sort, usually a long or BIGINTEGER count of milli-/nanoseconds. The current time thus looks/is stored like this:
1402401635000000 -- 2014-06-10 12:00:35.000000 GMT
You don't see the 'Year' value ('2014') in there, do you? In fact, there's a fair bit of complicated math to translate back and forth. So if you call any of the extraction/date part functions on the searched column, the server has to perform all that math just to figure out if you can include it in the results. On small tables this isn't an issue, but as the percentage of rows selected decreases this becomes a larger and larger drain. Then in this case, you're doing it a second time for asking about MONTH... well, you get the picture.
2. Unintended data:
Depending on the particular version of SQL Server, and column datatypes, using BETWEEN (or similar inclusive upper-bound ranges: <=) can result in the wrong data being selected. Essentially, you potentially end up including data from midnight of the "next" day, or excluding some portion of the "current" day's records.
What you should be doing:
So we need a way that's safe for our data, and will use indices (if viable). The correct way is then of the form:
WHERE date_created >= #startOfPreviousMonth AND date_created < #startOfCurrentMonth
Given that there's only one month, #startOfPreviousMonth can be easily substituted for/derived by:
DATEADD(month, -1, #startOfCurrentMonth)
If you need to derive the start-of-current-month in the server, you can do it via the following:
DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
A quick word of explanation here. The initial DATEDIFF(...) will get the difference between the start of the current era (0001-01-01 - AD, CE, whatever), essentially returning a large integer. This is the count of months to the start of the current month. We then add this number to the start of the era, which is at the start of the given month.
So your full script could/should look similar to the following:
DECLARE #startOfCurrentMonth DATETIME
SET #startOfCurrentMonth = DATEADD(month, DATEDIFF(month, 0, CURRENT_TIMESTAMP), 0)
SELECT *
FROM Member
WHERE date_created >= DATEADD(month, -1, #startOfCurrentMonth)
AND date_created < #startOfCurrentMonth
All date operations are thus only performed once, on one value; the optimizer is free to use indices, and no incorrect data will be included.
SELECT *
FROM Member
WHERE DATEPART(m, date_created) = DATEPART(m, DATEADD(m, -1, getdate()))
AND DATEPART(yyyy, date_created) = DATEPART(yyyy, DATEADD(m, -1, getdate()))
You need to check the month and year.
Add the options which have been provided so far won't use your indexes at all.
Something like this will do the trick, and make use of an index on the table (if one exists).
DECLARE #StartDate DATETIME, #EndDate DATETIME
SET #StartDate = dateadd(mm, -1, getdate())
SET #StartDate = dateadd(dd, datepart(dd, getdate())*-1, #StartDate)
SET #EndDate = dateadd(mm, 1, #StartDate)
SELECT *
FROM Member
WHERE date_created BETWEEN #StartDate AND #EndDate
DECLARE #StartDate DATETIME, #EndDate DATETIME
SET #StartDate = DATEADD(mm, DATEDIFF(mm,0,getdate())-1, 0)
SET #EndDate = DATEADD(mm, 1, #StartDate)
SELECT *
FROM Member
WHERE date_created BETWEEN #StartDate AND #EndDate
An upgrade to mrdenny's solution, this way you get exactly last month from YYYY-MM-01
Last month consider as till last day of the month.
31/01/2016 here last day of the month would be 31 Jan. which is not similar to last 30 days.
SELECT CONVERT(DATE, DATEADD(DAY,-DAY(GETDATE()),GETDATE()))
One way to do it is using the DATEPART function:
select field1, field2, fieldN from TABLE where DATEPART(month, date_created) = 4
and DATEPART(year, date_created) = 2009
will return all dates in april. For last month (ie, previous to current month) you can use GETDATE and DATEADD as well:
select field1, field2, fieldN from TABLE where DATEPART(month, date_created)
= (DATEPART(month, GETDATE()) - 1) and
DATEPART(year, date_created) = DATEPART(year, DATEADD(m, -1, GETDATE()))
declare #PrevMonth as nvarchar(256)
SELECT #PrevMonth = DateName( month,DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)) +
'-' + substring(DateName( Year, getDate() ) ,3,4)
SQL query to get record of the present month only
SELECT * FROM CUSTOMER
WHERE MONTH(DATE) = MONTH(CURRENT_TIMESTAMP) AND YEAR(DATE) = YEAR(CURRENT_TIMESTAMP);
SELECT * FROM Member WHERE month(date_created) = month(NOW() - INTERVAL 1 MONTH);
select * from [member] where DatePart("m", date_created) = DatePart("m", DateAdd("m", -1, getdate())) AND DatePart("yyyy", date_created) = DatePart("yyyy", DateAdd("m", -1, getdate()))
DECLARE #StartDate DATETIME, #EndDate DATETIME
SET #StartDate = DATEADD(mm, DATEDIFF(mm, 0, getdate()) - 1, 0)
SET #EndDate = dateadd(dd, -1, DATEADD(mm, 1, #StartDate))
SELECT * FROM Member WHERE date_created BETWEEN #StartDate AND #EndDate
and another upgrade to mrdenny's solution.
It gives the exact last day of the previous month as well.
WHERE
date_created >= DATEADD(MONTH, DATEDIFF(MONTH, 31, CURRENT_TIMESTAMP), 0)
AND date_created < DATEADD(MONTH, DATEDIFF(MONTH, 0, CURRENT_TIMESTAMP), 0)
I'm from Oracle env and I would do it like this in Oracle:
select * from table
where trunc(somedatefield, 'MONTH') =
trunc(sysdate -INTERVAL '0-1' YEAR TO MONTH, 'MONTH')
Idea: I'm running a scheduled report of previous month (from day 1 to the last day of the month, not windowed). This could be index unfriendly, but Oracle has fast date handling anyways.
Is there a similar simple and short way in MS SQL? The answer comparing year and month separately seems silly to Oracle folks.
You can get the last month records with this query
SELECT * FROM dbo.member d
WHERE CONVERT(DATE, date_created,101)>=CONVERT(DATE,DATEADD(m, datediff(m, 0, current_timestamp)-1, 0))
and CONVERT(DATE, date_created,101) < CONVERT(DATE, DATEADD(m, datediff(m, 0, current_timestamp)-1, 0),101)
I don't think the accepted solution is very index friendly
I use the following lines instead
select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date <= dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));
Or simply (this is the best).
select * from dbtable where the_date >= convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120) and the_date < SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
Some help
-- Get the first of last month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
-- Get the first of current month
SELECT convert(varchar(10),DATEADD(m, -1, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120);
--Get the last of last month except the last 3milli seconds. (3miliseconds being used as SQL express otherwise round it up to the full second (SERIUSLY MS)
SELECT dateadd(ms, -3, convert(varchar(10),DATEADD(m, 0, dateadd(d, - datepart(dd, GETDATE())+1, GETDATE())),120));
Here is what I did so I could put it in a view:
ALTER view [dbo].[MyView] as
with justdate as (
select getdate() as rightnow
)
, inputs as (
select dateadd(day, 1, EOMONTH(jd.rightnow, -2)) as FirstOfLastMonth
,dateadd(day, 1, EOMONTH(jd.rightnow, -1)) as FirstOfThisMonth
from justdate jd
)
SELECT TOP 10000
[SomeColumn]
,[CreatedTime]
from inputs i
join [dbo].[SomeTable]
on createdtime >= i.FirstOfLastMonth
and createdtime < i.FirstOfThisMonth
order by createdtime
;
Note that I intentionally ran getdate() once.
In Sql server for last one month:
select * from tablename
where order_date > DateAdd(WEEK, -1, GETDATE()+1) and order_date<=GETDATE()
DECLARE #curDate INT = datepart( Month,GETDATE())
IF (#curDate = 1)
BEGIN
select * from Featured_Deal
where datepart( Month,Created_Date)=12 AND datepart(Year,Created_Date) = (datepart(Year,GETDATE())-1)
END
ELSE
BEGIN
select * from Featured_Deal
where datepart( Month,Created_Date)=(datepart( Month,GETDATE())-1) AND datepart(Year,Created_Date) = datepart(Year,GETDATE())
END
DECLARE #StartDate DATETIME, #EndDate DATETIME
SET #StartDate = dateadd(mm, -1, getdate())
SET #StartDate = dateadd(dd, datepart(dd, getdate())*-1, #StartDate)
SET #EndDate = dateadd(mm, 1, #StartDate)
set #StartDate = DATEADD(dd, 1 , #StartDate)
The way I fixed similar issue was by adding Month to my SELECT portion
Month DATEADD(day,Created_Date,'1971/12/31') As Month
and than I added WHERE statement
Month DATEADD(day,Created_Date,'1971/12/31') = month(getdate())-1
If you are looking for last month so try this,
SELECT
FROM #emp
WHERE DATEDIFF(MONTH,CREATEDDATE,GETDATE()) = 1
If you are looking for last month so try this,
SELECT
FROM #emp
WHERE DATEDIFF(day,CREATEDDATE,GETDATE()) between 1 and 30
A simple query which works for me is:
select * from table where DATEADD(month, 1,DATEFIELD) >= getdate()
If you are looking for previous month data:
date(date_created)>=date_sub(date_format(curdate(),"%Y-%m-01"),interval 1 month) and
date(date_created)<=date_sub(date_format(curdate(),'%Y-%m-01'),interval 1 day)
This will also work when the year changes. It will also work on MySQL.