get last 3 month on year in sql server - sql

I want to get last 3 months name from current month. For example current month is December. So, I want get like this October, November and December.
This is my query:
SELECT CONVERT(CHAR, DATENAME(MONTH, IssueDate)) AS MonthName, ItemId
FROM dbo.Issue AS Issue
GROUP BY CONVERT(CHAR, DATENAME(MONTH, IssueDate)), ItemId
HAVING (ItemId = 427)
This returns:
But, my need is:
N.B. When December month close and January month open then October auto excluded as like (November, December and January)
this link is my Database only 2 table (size-243 KB with Zip) on the google drive https://goo.gl/S4m0R5

Add a date diff in a where clause to filter to the last 3 months, and then order by the month number at the end:
SELECT CONVERT(CHAR, DATENAME(MONTH, [IssueDate])) AS MonthName, ItemId
FROM [dbo].[Issue] AS Issue
WHERE datediff(m, [IssueDate], getdate()) between 0 and 2
GROUP BY CONVERT(CHAR, DATENAME(MONTH, [IssueDate])), ItemId, MONTH(IssueDate)
HAVING (ItemId= 427)
order by MONTH(IssueDate);

You can use DATEADD function:
WHERE IssueDate >= dateadd( month, -2, dateadd( day, -datepart( day, getdate() ) + 1, cast( getdate() as date ) ) )
That will give you IssueDate >= '2015-10-01' given today.
That will also work with index you have on IssueDate, if you start doing something like DATEADD / DATEDIFF etc. on IssueDate then the index can only be scanned end-to-end because it needs to processs all rows in the table so renders the index significantly less effective.

DECLARE #t TABLE
(
IssueDate DATETIME,
ItemId INT
)
INSERT INTO #t (IssueDate, ItemId)
VALUES
('20160105', 427),
('20151212', 427),
('20151213', 427),
('20151110', 427),
('20151001', 427),
('20150905', 427)
SELECT DATENAME(MONTH, dt)
FROM (
SELECT DISTINCT TOP(3) DATEADD(MONTH, DATEDIFF(MONTH, 0, IssueDate), 0) AS dt
FROM #t
WHERE ItemId = 427
ORDER BY dt DESC
) t
results -
------------------------------
January
December
November

You can use a recursive CTE to get month names for the last 12 months and then limit it to the last 3 month names in the second part of the query:
;WITH months(MonthNumber) AS
(
SELECT 0
UNION ALL
SELECT MonthNumber+1
FROM months
WHERE MonthNumber < 12
)
SELECT DATENAME(MONTH,DATEADD(MONTH,-MonthNumber,GETDATE())) AS [month]
FROM dbo.Issue AS Issue
CROSS JOIN months m
WHERE m.MonthNumber <3
GROUP BY DATENAME(MONTH,DATEADD(MONTH,-MonthNumber,GETDATE())) , ItemId
HAVING (ItemId = 427)

Related

SQL Server summarize by week starting monday

I need to summarize a revenue field by week, starting on Monday. My data looks as follows:
Date Rev
+----------+--------
4/10/2017 5
4/11/2017 6
4/12/2017 7
4/13/2017 8
4/17/2017 9
4/19/2017 12
I would like the data to show the first day of the week and the summary of that week like:
Date Rev
+----------+--------
4/10/2017 26
4/17/2017 21
How could I accomplish this?
select DATEADD(week, DATEDIFF(week,0, [date]) , 0) as [date], sum(rev)
from [data]
group by DATEADD(week, DATEDIFF(week,0, [date]) , 0)
order by [date]
SQLFiddle
This maps to your sample data. It works because day 0 (1/1/1900) just happened to fall on a Monday. If you needed to use Sunday or Tuesday as your start of week you would adjust your input dates and offset accordingly.
An example is here, you can use datepart function to easily get the result:
create table #temp
([Date] datetime, Rev int)
insert into #temp values ('2010-01-01',10)
insert into #temp values ('2010-01-02',20)
insert into #temp values ('2010-01-07',60)
insert into #temp values ('2010-01-09',50)
SELECT DATEPART (wk, [Date]) AS Week, Sum(Rev) AS TotalRev
FROM #temp
Group By DATEPART (wk, [Date]);
Edit:
If you are insisting on using the first date value instead of week number, this is an alternative solution for you:
;with cte (firstdateofweek,weekno) as
(
select min([Date]) as firstdateofweek ,DATEPART (wk, [Date]) weekno
from #temp
group by DATEPART (wk, [Date])
)
SELECT cte.firstdateofweek AS Week,sum(Rev) AS Sales
FROM #temp
INNER JOIN cte on DATEPART(wk, [Date]) = cte.weekno
Group By cte.firstdateofweek

How To Select Records in a Status Between Timestamps? T-SQL

I have a T-SQL Quotes table and need to be able to count how many quotes were in an open status during past months.
The dates I have to work with are an 'Add_Date' timestamp and an 'Update_Date' timestamp. Once a quote is put into a 'Closed_Status' of '1' it can no longer be updated. Therefore, the 'Update_Date' effectively becomes the Closed_Status timestamp.
I'm stuck because I can't figure out how to select all open quotes that were open in a particular month.
Here's a few example records:
Quote_No Add_Date Update_Date Open_Status Closed_Status
001 01-01-2016 NULL 1 0
002 01-01-2016 3-1-2016 0 1
003 01-01-2016 4-1-2016 0 1
The desired result would be:
Year Month Open_Quote_Count
2016 01 3
2016 02 3
2016 03 2
2016 04 1
I've hit a mental wall on this one, I've tried to do some case when filtering but I just can't seem to figure this puzzle out. Ideally I wouldn't be hard-coding in dates because this spans years and I don't want to maintain this once written.
Thank you in advance for your help.
You are doing this by month. So, three options come to mind:
A list of all months using left join.
A recursive CTE.
A number table.
Let me show the last:
with n as (
select row_number() over (order by (select null)) - 1 as n
from master..spt_values
)
select format(dateadd(month, n.n, q.add_date), 'yyyy-MM') as yyyymm,
count(*) as Open_Quote_Count
from quotes q join
n
on (closed_status = 1 and dateadd(month, n.n, q.add_date) <= q.update_date) or
(closed_status = 0 and dateadd(month, n.n, q.add_date) <= getdate())
group by format(dateadd(month, n.n, q.add_date), 'yyyy-MM')
order by yyyymm;
This does assume that each month has at least one open record. That seems reasonable for this purpose.
You can use datepart to extract parts of a date, so something like:
select datepart(year, add_date) as 'year',
datepart(month, date_date) as 'month',
count(1)
from theTable
where open_status = 1
group by datepart(year, add_date), datepart(month, date_date)
Note: this counts for the starting month and primarily to show the use of datepart.
Updated as misunderstood the initial request.
Consider following test data:
DECLARE #test TABLE
(
Quote_No VARCHAR(3),
Add_Date DATE,
Update_Date DATE,
Open_Status INT,
Closed_Status INT
)
INSERT INTO #test (Quote_No, Add_Date, Update_Date, Open_Status, Closed_Status)
VALUES ('001', '20160101', NULL, 1, 0)
, ('002', '20160101', '20160301', 0, 1)
, ('003', '20160101', '20160401', 0, 1)
Here is a recursive solution, that doesn't rely on system tables BUT also performs poorer. As we are talking about months and year combinations, the number of recursions will not get overhand.
;WITH YearMonths AS
(
SELECT YEAR(MIN(Add_Date)) AS [Year]
, MONTH(MIN(Add_Date)) AS [Month]
, MIN(Add_Date) AS YMDate
FROM #test
UNION ALL
SELECT YEAR(DATEADD(MONTH,1,YMDate))
, MONTH(DATEADD(MONTH,1,YMDate))
, DATEADD(MONTH,1,YMDate)
FROM YearMonths
WHERE YMDate <= SYSDATETIME()
)
SELECT [Year]
, [Month]
, COUNT(*) AS Open_Quote_Count
FROM YearMonths ym
INNER JOIN #test t
ON (
[Year] * 100 + [Month] <= CAST(FORMAT(t.Update_Date, 'yyyyMM') AS INT)
AND t.Closed_Status = 1
)
OR (
[Year] * 100 + [Month] <= CAST(FORMAT(SYSDATETIME(), 'yyyyMM') AS INT)
AND t.Closed_Status = 0
)
GROUP BY [Year], [Month]
ORDER BY [Year], [Month]
Statement is longer, also more readable and lists all year/month combinations to date.
Take a look at Date and Time Data Types and Functions for SQL-Server 2008+
and Recursive Queries Using Common Table Expressions

How to group by month and year for entire calender year until this month in SQL

I have this query
DECLARE #DATE datetime
SELECT #Date = '2014-04-01'
SELECT #Date, COUNT(*) FROM Claim C
INNER JOIN Prop_Vehicles PV ON PV.Prop = C.Prop
WHERE PV.Vehicle IN (1,2) AND
C.DateCreate >= #DATE AND
ClaimCodeId =5
I want to group by month wise for the calnder year. For example
April 2014 - 200
May 2014 - 300
June 2014 - 500
.
.
october 2014 - 100
something like this. How to achieve it? Could someone help me how to split #Date into two fields and also group by month year wise until current month like I mentioned above?
I reckon datepart function would do? Let me also check that.
Thank you in advance.
In case some months don't have data then this would skip those months.
If you want all months data even if value is zero, then you need to construct months table and join with it
SELECT DATEADD(MONTH, DATEDIFF(MONTH,0,C.DateCreate), 0), COUNT(*) FROM Claim C
INNER JOIN Prop_Vehicles PV ON PV.Prop = C.Prop
and PV.Vehicle IN (1,2) AND
and C.DateCreate >= #DATE AND
AND ClaimCodeId =5
group by DATEADD(MONTH, DATEDIFF(MONTH,0,C.DateCreate), 0)
as per latest comment
here is the way to get all months data and also to display year and month
DECLARE #DATE datetime
SELECT #Date = '2014-04-01'
;with cte
as
(
select DATEADD(month, datediff(month,0,#Date), 0) as monthVal,1 as N
union all
select DATEADD(month, datediff(month,0,#Date)+N, 0) as monthVal, N+1
FROM cte
WHERE n <=5
)
SELECT DATENAME(year, monthval) as Year, datename(month,monthVal) as Month, COUNT(*) FROM
cte
left join Claim C
on DATEADD(month, datediff(month,0,C.DAteCreate)= cte.monthVal
INNER JOIN Prop_Vehicles PV ON PV.Prop = C.Prop
and PV.Vehicle IN (1,2) AND
and C.DateCreate >= #DATE AND
AND ClaimCodeId =5
group by DATENAME(year, monthval) , datename(month,monthVal)

Data appear at least once for every month in the last X month

My problem:
Table: trans_detail:
PhoneNo | Datetime
01234 | 2013-01-05 20:40:10
01245 | 2013-04-02 21:00:13
05678 | 2013-04-16 01:24:07
04567 | 2013-07-23 07:00:00
etc | etc
I want to get all phoneNo that appears at least once for every month in the last X month (X month can be any month between 1-12).
For example: get all phone no. that appears at least once for Every Month in the last 3 months.
I am using SQL Server 2005.
Here is a quick query that comes close to what you want:
select PhoneNo
from trans_detail d
where d.datetime >= dateadd(mm, -#X, getdate())
group by PhoneNo
having count(distinct year(datetime)*12+month(datetime)) = #X
The where clause filters the data to only include rows in the last #X months. the having clause checks that each month is in the data, by counting the number of distinct months.
The above version of the query assumes that you mean calendar months. So, it has boundary condition problems. If you run it on June 16th, then it looks back one month and makes sure that the phone number appears at least once since May 16th. I am unclear on whether you want to insist that the number appear twice (once in May and once in June) or if once (once during the time period). The solution to this is to move the current date back to the end of the previous month:
select PhoneNo
from trans_detail d cross join
(select cast(getdate() - day(getdate) + 1 as date) as FirstOfMonth const
where d.datetime >= dateadd(mm, -#X, FirstOfMonth) and
d.datetime < FirstOfMonth
group by PhoneNo
having count(distinct year(datetime)*12+month(datetime)) = #X
Here it is. First two CTEs are to find and prepare last X months, third CTE is to group your data by phones and months. At the end just join the two and return where number of matching rows are equal to number of months.
DECLARE #months INT
SET #Months = 3
;WITH CTE_Dates AS
(
SELECT GETDATE() AS Dt
UNION ALL
SELECT DATEADD(MM,-1,Dt) FROM CTE_Dates
WHERE DATEDIFF(MM, Dt,GETDATE()) < #months-1
)
, CTE_Months AS
(
SELECT MONTH(Dt) AS Mn, YEAR(Dt) AS Yr FROM CTE_Dates
)
, CTE_Trans AS
(
SELECT PhoneNo, MONTH([Datetime]) AS Mn, YEAR([Datetime]) AS Yr FROM dbo.trans_detail
GROUP BY PhoneNo, MONTH([Datetime]), YEAR([Datetime])
)
SELECT PhoneNo FROM CTE_Months m
LEFT JOIN CTE_Trans t ON m.Mn = t.Mn AND m.Yr = t.Yr
GROUP BY PhoneNo
HAVING COUNT(*) = #months
SQLFiddle Demo - with added some more data that will match for last 3 months

tsql month problem

I have a table like:
id month cost
------------------
1 Jan 200
1 Mar 204
1 May 200
1 Dec 201
I need an output like( order by month including the other months of a year-displaying all 12 months):
to month cost
------------------
1 Jan 200
NULL Feb NULL
1 Mar 204
....
....
....
1 Dec 201
any idea or solution how to do this in TSQL?
Thanks!
edit:: month is extracted from a datetime value.
in real world i'll have to show previous 12 months from last month in a DESC order! any suggestion for that?
Try building a reference table of months, and JOINing on it. It's the quickest way to do this with months in varchar datatype.
declare #foo table (id int, [mon] varchar(100), cost int)
declare #mon table (mon varchar(100), orderWeight int)
INSERT INTO #mon (mon, orderWeight)
VALUES ('Jan',1), ('Feb',2),('Mar',3),('Apr',4),('May',5),('Jun',6),('Jul',7),
('Aug',8),('Sep',9),('Oct',10),('Nov',11),('Dec',12)
INSERT INTO #foo(id, [mon], cost)
VALUES ( 1 ,'Jan' , 200),
( 1 ,'Mar', 204),
( 1 ,'May' , 200),
( 1 ,'Dec' , 201)
select f.id,
m.[mon] ,
f.cost
from #mon as m
left join #foo as f on m.mon = f.mon
order by m.orderWeight
Results:
Your ordering will now be guaranteed with the order by orderWeight.
Sample table
create table mytable(id int, dt datetime, cost money)
insert mytable values
(1,GETDATE()-10,200),
(1,GETDATE()-40,204),
(1,GETDATE()-100,200),
(1,GETDATE()-200,201);
The query, using SQL Server 2008 specific syntax, and sorted properly
select
t.id [to],
CONVERT(char(3),dateadd(month,-M.N,L.PVT),7) [Month],
sum(t.cost) totalCost
from (select PVT=dateadd(month,datediff(month,0,getdate())-1,0)) L
cross join (values (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11)) M(N)
left join mytable t
on t.dt >= dateadd(month,-M.N,L.PVT)
and t.dt < dateadd(month,-M.N+1,L.PVT)
group by t.id, right(CONVERT(char(9),dt,6),6), M.N, L.PVT
order by M.N
What it does:
right(CONVERT(char(9),dt,6),6) converts a date into the format 'DD MMM YY', we only need the MMM YY part
In the SELECT, we further extract only the 3-char month from it, using LEFT( , 3)
The subquery L has a single record and column, PVT, which is the first date of the last month
The number series 0-11 is used to create the month values for the last 12 months, using the formula dateadd(month,-M.N,L.PVT)
The range t.dt >= .. and t.dt < .. finds data for a single month
How about this?
The result contains month and year, but you can strip it as you want.
;with months
as
(
select dateadd(month, -1, dateadd(day, datediff(day, 0, getdate()), 0)) as m
union all
select dateadd(month, -1, m)
from months
where m > dateadd(month, -12, getdate())
)
-- Testdata
,yourTable(id,somedate,cost)
as
(
select 1, '2011-01-03', 200
union all
select 1, '2011-03-06', 204
union all
select 1, '2010-05-09', 200
union all
select 1, '2010-05-19', 201
union all
select 1, '2010-12-02', 201
)
-- end testdata
select yt.id
,datename(month,coalesce(yt.somedate, m.m)) as [month]
,datename(year,coalesce(yt.somedate, m.m)) as [year]
--,yt.cost
,sum(yt.cost) as cost
from months m
left join yourTable yt
on datepart(year, yt.someDate) = DATEPART(year, m.m)
and datepart(month, yt.someDate) = DATEPART(month, m.m)
group by
yt.id
,datename(month,coalesce(yt.somedate, m.m))
,datename(year,coalesce(yt.somedate, m.m))
,m.m
order by m.m desc
Edit: Altered solution to support sum.
Remove the group by-section and alter the comment of cost, to get the old solution.