I checked Get the records of last month in SQL server and it did not work!
I try to get the records of last month based on my database table and column issue_date.
What's the SQL query to do this?
For clarification, today (27-April-18) I want to get all records from March-18.
I have the issue_date in the format that I convert to date but below code gives me all records from 01-March-2018 to and including today.
DATEPART(month, CONVERT (VARCHAR(11),DATEADD(day,wo_header.issue_date,`1971/12/31`),106)) = DATEPART(month, DATEADD(month, -1, getdate()))
To get firstDay and lastDay of previous month
DECLARE #FirstDayOfLastMonth DATETIME = CONVERT(DATE, DATEADD(d, -(DAY(DATEADD(m, -1, GETDATE() - 2))), DATEADD(m, -1, GETDATE() - 1))),
#LastDayOfLastMonth DATETIME = CONVERT(DATE, DATEADD(d, -(DAY(GETDATE())), GETDATE()))
SELECT #FirstDayOfLastMonth, #LastDayOfLastMonth
Your required Query
SELECT *
FROM TABLE
WHERE CAST(issue_date AS DATE) BETWEEN CONVERT(DATE, DATEADD(d, -(DAY(DATEADD(m, -1, GETDATE() - 2))), DATEADD(m, -1, GETDATE() - 1))) AND CONVERT(DATE, DATEADD(d, -(DAY(GETDATE())), GETDATE()))
Perhaps the easiest method is eomonth(). If there is no time component on issuedate:
where issuedate > eomonth(getdate(), -2) and
issuedate <= eomonth(getdate(), -1)
If there is a time component:
where issuedate >= dateadd(day, 1, cast(eomonth(getdate(), -2) as date)) and
issuedate < dateadd(day, 1, cast(eomonth(getdate(), -1) as date))
Without eomonth, I would do:
where issuedate < cast(dateadd(day, 1 - day(getdate()), getdate()) as date) and
issuedate >= dateadd(month, -1, cast(dateadd(day, 1 - day(getdate()), getdate()) as date))
The code I figured out is not pretty but it works. It first adds extra column with the month number to the SELECT portion of my code:
Month(CONVERT (VARCHAR(11),DATEADD(day,wo_header.closing_date,'1971/12/31'),106)) As Month
And than is used for WHERE statement:
Month(CONVERT (VARCHAR(11),DATEADD(day,wo_header.closing_date,'1971/12/31'),106)) = month(getdate())-1
So for anyone like me working in SQL report kind-of environment it should work.
I'm trying to write a stored procedure which groups up rows based on their month and return a sum of all items if they exist and 0 if they don't.
For the date part of the query, what I am trying to get is today's date - extract the month and go back 5 months to gather any data if it exists.
At this stage, the query runs fine as is but I'm wondering if there's any way to optimise this as it looks like I'm running the same set of data over and over again and also it's hard coded to an extent.
The dataset I am trying to achieve is as follows:
Month TotalAmount TotalCount
-----------------------------------
2017-11 0 0
2017-12 200.00 2
2018-01 300.00 3
2018-02 0 0
2018-03 300.00 3
2018-04 100.00 1
Using the following query below, I was able to achieve what I want but as you can see, it's hard coding back the past 5 months so if I wanted to go back 12 months, I'd have to add in more code.
DECLARE #5MonthAgo date = CAST(DATEADD(MONTH, -5, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -5, GETDATE())) AS DATE)
DECLARE #4MonthAgo date = CAST(DATEADD(MONTH, -4, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -4, GETDATE())) AS DATE)
DECLARE #3MonthAgo date = CAST(DATEADD(MONTH, -3, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -3, GETDATE())) AS DATE)
DECLARE #2MonthAgo date = CAST(DATEADD(MONTH, -2, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -2, GETDATE())) AS DATE)
DECLARE #1MonthAgo date = CAST(DATEADD(MONTH, -1, GETDATE()) + 1 - DATEPART(DAY, DATEADD(MONTH, -1, GETDATE())) AS DATE)
DECLARE #CurrentMonth date = CAST(GETDATE() + 1 - DATEPART(DAY, GETDATE()) AS DATE)
-- Table to return grouped and sum data
DECLARE #StatsTable TABLE ([Month] DATE,
[Total Amount] DECIMAL(18,2),
[Total Count] INT
)
-- Temporary table to hold onto data batch - so table isn't used later on
DECLARE #TempGenTable TABLE ([Id] INT,
[Date] DATETIME,
[Lines] INT NULL,
[Amount] DECIMAL(18, 2) NULL
)
INSERT INTO #TempGenTable
SELECT
Id, Date, Lines, Amount
FROM
TallyTable
WHERE
Date >= #5MonthAgo
INSERT INTO #StatsTable
SELECT
#5MonthAgo,
COALESCE((SELECT SUM(Amount)
FROM #TempGenTable
WHERE Date >= #5MonthAgo AND Date < #4MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0),
COALESCE((SELECT COUNT(Id)
FROM #TempGenTable
WHERE Date >= #5MonthAgo AND Date < #4MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0)
UNION
SELECT
#4MonthAgo,
COALESCE((SELECT SUM(Amount)
FROM #TempGenTable
WHERE Date >= #4MonthAgo AND Date < #3MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0),
COALESCE((SELECT COUNT(Id)
FROM #TempGenTable
WHERE Date >= #4MonthAgo AND Date < #3MonthAgo
GROUP BY DATEADD(MONTH, DATEDIFF(MONTH, 0, Date), 0)), 0)
...
Is there an easier way to be able to get the above data with more flexibility in the number of months?
Is it better to just have the query pass in a month variable and it checks just the current month and have a loop within the controller to go back x number of months?
I would generate the data using a recursive CTE and then use left join:
with months as (
select datefromparts(year(getdate()), month(getdate()), 1) as month_start, 5 as n
union all
select dateadd(month, -1, month_start), n - 1
from months
where n > 0
)
select m.month_start, count(s.id), sum(s.amount)
from months m left join
#StatsTable s
on m.month_start = s.month
group by m.month_start
order by m.month_start;
You haven't provided sample data, so I'm not sure what s.month looks like. You might want the join condition to be:
on s.month >= m.month_start and s.month < dateadd(month, 1, m.month_start)
Below is a set-based method to generate the needed monthly periods:
--sample data
CREATE TABLE dbo.TallyTable (
Id int
, Date datetime
, Lines int
, Amount decimal(18, 2)
);
INSERT INTO dbo.TallyTable
VALUES
(1, '2017-12-05', 1, 50.00)
,(2, '2017-12-06', 1, 150.00)
,(3, '2018-01-10', 1, 100.00)
,(4, '2018-01-11', 1, 100.00)
,(5, '2018-01-12', 1, 100.00)
,(6, '2018-03-15', 1, 225.00)
,(7, '2018-03-15', 1, 25.00)
,(8, '2018-03-15', 1, 50.00)
,(9, '2018-04-20', 1, 100.00);
GO
DECLARE #Months int = 5; --number of historical months
WITH
t10 AS (SELECT n FROM (VALUES(0),(0),(0),(0),(0),(0),(0),(0),(0),(0)) t(n))
,t100 AS (SELECT ROW_NUMBER() OVER (ORDER BY (SELECT 0)) - 1 AS num FROM t10 AS a CROSS JOIN t10 AS b)
, periods AS (SELECT
CONVERT(varchar(7), DATEADD(month, DATEDIFF(month, '', GETDATE()) - num, ''),121) AS Month
, DATEADD(month, DATEDIFF(month, '', CAST(GETDATE() AS date)) - num, '') AS PeriodStart
, DATEADD(month, DATEDIFF(month, '', CAST(GETDATE() AS date)) - num + 1, '') AS NextPeriodStart
FROM t100
WHERE num <= #Months
)
SELECT periods.Month, COALESCE(SUM(Amount), 0) AS TotalAmount, COALESCE(COUNT(ID), 0) AS TotalCount
FROM periods
LEFT JOIN dbo.TallyTable ON
TallyTable.Date >= PeriodStart
AND TallyTable.Date < NextPeriodStart
GROUP BY periods.Month
ORDER BY periods.Month;
Right now I'm using this command to retrieve all fields from the current day:
SELECT COUNT(*)
FROM [SecureOrders]
WHERE DateTime >= DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0)
AND
DateTime < DATEADD(day, DATEDIFF(day, 0, GETDATE()), 1)
However, I want to be able to get the fields that were entered between noon yesterday and noon today - how can I go about doing that?
0.5 is noon (eg half a day)
WHERE DateTime >= DATEADD(day, DATEDIFF(day, 0, GETDATE()), -0.5)
AND
DateTime < DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0.5)
DECLARE #NoonToday DATETIME;
SET #NoonToday = DATEADD(HOUR, 12, DATEDIFF(DAY, 0, CURRENT_TIMESTAMP));
SELECT COUNT(*) FROM [SecureOrders]
WHERE [DateTime] >= DATEADD(DAY, -1, #NoonToday)
AND [DateTime] < #NoonToday;
it might seem ugly but should work
SELECT
COUNT(*)
FROM
[SecureOrders]
WHERE
DateTime >= DATEADD(day, DATEDIFF(day, 0, GETDATE()), 0) - 0.5 AND DateTime < DATEADD(day, DATEDIFF(day, 0, GETDATE()), 1) + 0.5
A variation on #Aaron Bertrand's solution, without declaring a variable and without treating a non-zero integer value as a date:
SELECT COUNT(*)
FROM SecureOrders o
CROSS JOIN (
SELECT DATEADD(HOUR, DATEDIFF(DAY, 0, GETDATE()) * 24 + 12, 0)
) AS d (TodayNoon)
WHERE o.DateTime < d.TodayNoon
AND o.DateTime >= DATEADD(DAY, -1, d.TodayNoon)
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.