How to select month wise data for year from sql server - sql

I have a user table where data is about 20 years old.
I want to fetch month wise data from CreatedOn column that is (2014-07-08 17:44:00) and if data is not available for any month then I want 0 for this month
Example
Month data year
jan 34 2014
feb 56 2014
march 0 2014
apr 23 2014
I am using the following query but it's not working:
with cte(monno , monname ) as(
select 1, 'Jan' union all
select 2, 'Feb' union all
select 3, 'Mar' union all
select 4, 'Apr' union all
select 5, 'May' union all
select 6, 'Jun' union all
select 7, 'Jul' union all
select 8, 'Aug' union all
select 9, 'Sep' union all
select 10, 'Oct' union all
select 11, 'Nov' union all
select 12, 'Dec'
)
SELECT DISTINCT monname
,monno
,count(CreatedOn) OVER (PARTITION BY datepart(year, CreatedOn),DATEPART(MONTH, CreatedOn))
FROM Contributors_tbl a
RIGHT JOIN cte b ON DATEPART(MONTH, CreatedOn) = b.monno
AND datepart(year, CreatedOn) = 2014
ORDER BY monno

Try this Way to find Month Number AND Month Name
CREATE TABLE #TempMonth
(
MonthNum int,
MonthNames varchar(50)
)
INSERT INTO #TempMonth
SELECT STR(MONTH(DATEADD(mm, number, GETDATE())), 2) AS MonthNum,
DATENAME(month, DATEADD(month, MONTH(DATEADD(mm, number, GETDATE())), 0) - 1) AS MonthNames
FROM master.dbo.spt_values
WHERE (name IS NULL) AND (number BETWEEN 0 AND 11) ORDER BY STR(MONTH(DATEADD(mm, number, GETDATE())), 2)
SELECT * FROM #TempMonth
select distinct MonthNames,MonthNum,
count(CreatedOn) over(partition by datepart(year,CreatedOn),DATEPART(MONTH,CreatedOn))
from Contributors_tbl a
right join #TempMonth b on DATEPART(MONTH,CreatedOn) = b.MonthNum and datepart(year,CreatedOn) = 2014
order by MonthNum
DROP Table #TempMonth

Try This
with cte(monno , monname ) as(
select 1, 'Jan' union all
select 2, 'Feb' union all
select 3, 'Mar' union all
select 4, 'Apr' union all
select 5, 'May' union all
select 6, 'Jun' union all
select 7, 'Jul' union all
select 8, 'Aug' union all
select 9, 'Sep' union all
select 10, 'Oct' union all
select 11, 'Nov' union all
select 12, 'Dec'
)
select monname,
monno,
coalesce(cnt,0) as cnt
from cte c
outer apply (
select count(*) as cnt
from Contributors_tbl
where CreatedOn >= DATEADD(mm,c.monno - 1,'20140101')
And CreatedOn < DATEADD(mm,c.monno,'20140101')
)t
order by monno

Related

SQL: Create multiple rows for a record based on months between two dates

My table has records as below for different Id's and different start and end dates
ID, Startdate, Enddate
1, 2017-02-14, 2018-11-05
I want to write an SQL without using date dimension table that gives below output: Basically one record for each month between start and end date.
1, 2017, 02
1, 2017, 03
1, 2017, 04
1, 2017, 05
1, 2017, 06
1, 2017, 07
1, 2017, 08
1, 2017, 09
1, 2017, 10
1, 2017, 11
1, 2017, 12
1, 2018, 01
1, 2018, 02
1, 2018, 03
1, 2018, 04
1, 2018, 05
1, 2018, 06
1, 2018, 07
1, 2018, 09
1, 2018, 10
1, 2018, 11
Please use below query example:
set #start_date = '2017-02-14';
set #end_date = LAST_DAY('2018-11-05');
WITH RECURSIVE date_range AS
(
select MONTH(#start_date) as month_, YEAR(#start_date) as year_, DATE_ADD(#start_date, INTERVAL 1 MONTH) as next_month_date
UNION
SELECT MONTH(dr.next_month_date) as month_, YEAR(dr.next_month_date) as year_, DATE_ADD(dr.next_month_date, INTERVAL 1 MONTH) as next_month_date
FROM date_range dr
where next_month_date <= #end_date
)
select month_, year_ from date_range
order by next_month_date desc
This is what I did and it worked like a charm:
-- sample data
WITH table_data
AS (
SELECT 1 AS id
,cast('2017-08-14' AS DATE) AS start_dt
,cast('2018-12-16' AS DATE) AS end_dt
UNION ALL
SELECT 2 AS id
,cast('2017-09-14' AS DATE) AS start_dt
,cast('2019-01-16' AS DATE) AS end_dt
)
-- find minimum date from the data
,starting_date (start_date)
AS (
SELECT min(start_dt)
FROM TABLE_DATA
)
--get all months between min and max dates
,all_dates
AS (
SELECT last_day(add_months(date_trunc('month', start_date), idx * 1)) month_date
FROM starting_date
CROSS JOIN _v_vector_idx
WHERE month_date <= add_months(start_date, abs(months_between((
SELECT min(start_dt) FROM TABLE_DATA), (SELECT max(end_dt) FROM TABLE_DATA))) + 1)
ORDER BY month_date
)
SELECT id
,extract(year FROM month_date)
,extract(month FROM month_date)
,td.start_dt
,td.end_dt
FROM table_data td
INNER JOIN all_dates ad
ON ad.month_date > td.start_dt
AND ad.month_date <= last_day(td.end_dt)
ORDER BY 1
,2
You have to generate date and from that have to pick year and month
select distinct year(date),month( date) from
(select * from (
select
date_add('2017-02-14 00:00:00.000', INTERVAL n5.num*10000+n4.num*1000+n3.num*100+n2.num*10+n1.num DAY ) as date
from
(select 0 as num
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9) n1,
(select 0 as num
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9) n2,
(select 0 as num
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9) n3,
(select 0 as num
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9) n4,
(select 0 as num
union all select 1
union all select 2
union all select 3
union all select 4
union all select 5
union all select 6
union all select 7
union all select 8
union all select 9) n5
) a
where date >'2017-02-14 00:00:00.000' and date < '2018-11-05'
) as t

Create financial report with SQL

I want to create a financial report using a select statement for example: my start month is april 2000 and the end month is march 2001 how can I do that?
SELECT monthList.MonthName ,transcation.id,transaction.amount(
SELECT 10 ordby, 'January' MonthName
UNION SELECT 11, 'February'
UNION SELECT 12, 'March'
UNION SELECT 1, 'April'
UNION SELECT 2,'May'
UNION SELECT 3,'June'
UNION SELECT 4,'July'
UNION SELECT 5,'August'
UNION SELECT 6,'September'
UNION SELECT 7,'October'
UNION SELECT 8,'November'
UNION SELECT 9,'December') monthList
left JOIN (select YEAR(Date) [Year], MONTH(Date) [Month],DATENAME(MONTH,Date) [Month Name],sum(Amount)as amount
FROM transaction
where id=2 GROUP BY YEAR(Date), MONTH(Date),DATENAME(MONTH, Date) ) as t on t.[Month Name]=monthList.[Month Name])

Dynamic column name change based on date [T-SQL]

Is there a way to make this work? change static, "13MonthsAgo"
into January?
Original
> COUNT(CASE WHEN dateadd(MONTH, - 13, getdate()) >
> HireDate AND dateadd(MONTH, - 13, getdate()) <
> TerminationDate OR
>TerminationDate IS NULL THEN 1 ELSE NULL END) AS 13Monthsago
Preferred
> COUNT(CASE WHEN dateadd(MONTH, - 13, getdate()) >
> HireDate AND dateadd(MONTH, - 13, getdate()) <
> TerminationDate OR
>TerminationDate IS NULL THEN 1 ELSE NULL END) AS
>DATENAME(month, dateadd(MONTH,-13,getdate()))
A lengthy approach but will work..
declare #MonthName varchar(20)
select 1 num, 'January' name into #Months
union
select 2 num, 'February' name
union
select 3 num, 'March' name
union
select 4 num, 'April' name
union
select 5 num, 'May' name
union
select 6 num, 'June' name
union
select 7 num, 'July' name
union
select 8 num, 'August' name
union
select 9 num, 'September' name
union
select 10 num, 'October' name
union
select 11 num, 'November' name
union
select 12 num, 'December' name
select #MonthName = name from #Months where datepart(mm,getdate()) = num
--Add the other columns to the dataset here
--This is just an example
select HireDate, TerminationDate,
COUNT(CASE WHEN dateadd(MONTH, - 13, getdate()) >
HireDate AND dateadd(MONTH, - 13, getdate()) <
TerminationDate OR
TerminationDate IS NULL THEN 1 ELSE NULL END) AS 13Monthsago
into #Dataset
FROM SomeTable GROUP BY HireDate, TerminationDate
use tempdb
EXEC sp_RENAME '#Dataset.13Monthsago' , #MonthName, 'COLUMN'
SELECT * FROM #Dataset
This could be one way to go about it.
;with cte_Dates AS
(
SELECT CAST('20150101' as DATEtime) as DateStr UNION ALL
SELECT '20150201' UNION ALL
SELECT '20150202' UNION ALL
SELECT '20150203' UNION ALL
SELECT '20150204' UNION ALL
SELECT '20150301' UNION ALL
SELECT '20150401' UNION ALL
SELECT '20150501' UNION ALL
SELECT '20150601' UNION ALL
SELECT '20150701' UNION ALL
SELECT '20150801' UNION ALL
SELECT '20150901' UNION ALL
SELECT '20151001' UNION ALL
SELECT '20151101' UNION ALL
SELECT '20151201'
)
SELECT *
FROM
(SELECT DateStr,DATENAME(MONTH,DateStr) As MONTHS
FROM
cte_Dates
)P
PIVOT
(
count(DateStr)
FOR MONTHS IN ([January], [February],[March],[April],[May],[June],[July],[August],[September],[October],[November],[December])
)AS PVT

Sql query for aggregation

Let consider the below table structure
Product Year Month Price
A 2011 01 23
A 2011 02 34
.......
.....
A 2011 12 54
B 2011 01 13
B 2011 02 12
.......
.....
B 2011 12 20
From this table i need to aggregate the value for every 3 months ie..,
Product Year Month Price
A 2011 1-3 45
A 2011 4-6 23
A 2011 7-9 45
A 2011 10-12 16
A 2012 1-3 12
.......
.......
Can anybody tell me how to do this calculation using sql query...
Thanks in Advance !!!
Try this. Use Case statement to group the month Quarter wise then find the sum of price
SELECT product,
[year],
CASE
WHEN ( [month] ) IN( '01', '02', '03' ) THEN '1-3'
WHEN ( [month] ) IN( '04', '05', '06' ) THEN '4-6'
WHEN ( [month] ) IN( '07', '08', '09' ) THEN '7-9'
WHEN ( [month] ) IN( '10', '11', '12' ) THEN '10-12'
END [Month],
Sum(Price)
FROM tablename
GROUP BY product,
[year],
CASE
WHEN ( [month] ) IN( '01', '02', '03' ) THEN '1-3'
WHEN ( [month] ) IN( '04', '05', '06' ) THEN '4-6'
WHEN ( [month] ) IN( '07', '08', '09' ) THEN '7-9'
WHEN ( [month] ) IN( '10', '11', '12' ) THEN '10-12'
END
Note : By looking at your month data it looks like its a varchar column but you can change it to TINYINT
Try using CASE in GROUP BY clause:
...
GROUR BY [Year], CASE WHEN Month in (1,2,3) THEN '1-3'
WHEN Month in (4,5,6) THEN '4-6'
...
END
Considering Month is stored as varchar(), you can write as:
Select Product,
Year,
[MonthRange] as [Month],
Sum(Price)
From (
select Product,
Year,
case when Month in ('01','02','03') then '[1-3]'
when Month in ('04','05','06') then '[4-6]'
when Month in ('07','08','09') then '[7-9]'
when Month in ('10','11','12') then '[10-12]'
end as [MonthRange],
Price
from #test) as T
Group by Product,Year,[MonthRange]
DEMO
select Product, [year], case when [month] between 1 and 3 then '01-03' else case when [month] between 4 and 6 then '04-06' else case when [month] between 7 and 9 then '07-09' else '10-12' end end end, sum([price])
from Table1
group by Product, [year], case when [month] between 1 and 3 then '01-03' else case when [month] between 4 and 6 then '04-06' else case when [month] between 7 and 9 then '07-09' else '10-12' end end end
Above sql query will give you the required results, if you don not use leading zeros which I used in month labels then you will not get result sorted by month.
Use this query.
CREATE table #test
(
product VARCHAR(10),
year int,
month int,
price int
)
INSERT INTO #test
SELECT 'A', 2011, 01, 23 UNION
SELECT 'A', 2011, 02, 65 UNION
SELECT 'A', 2011, 03, 45 UNION
SELECT 'B', 2011, 04, 34 UNION
SELECT 'B', 2011, 05, 67 UNION
SELECT 'B', 2011, 06, 34 UNION
SELECT 'B', 2011, 07, 87 UNION
SELECT 'B', 2011, 08, 2 UNION
SELECT 'B', 2011, 09, 345 UNION
SELECT 'B', 2011, 10, 9 UNION
SELECT 'B', 2011, 11, 293 UNION
SELECT 'B', 2011, 12, 23
SELECT product, [year], [MONTH], SUM(price)
FROM
(
SELECT product, [year], CASE WHEN [MONTH] IN (01,02,03) THEN '1-3'
WHEN [MONTH] IN (04,05,06) THEN '4-6'
WHEN [MONTH] IN (07,08,09) THEN '7-9'
WHEN [MONTH] IN (10, 11, 12) THEN '10-12'
END AS [Month],
price
FROm #Test
)AS A
group BY product, [year], [Month]

Calculating a summary of previously calculated data

Quick question about summary data:
I have the below code which will pull sales information and put it into a month/year grid, which is terrific (http://sqlfiddle.com/#!3/9d79e/1):
WITH
months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12),
years AS (SELECT 2011 AS yr UNION ALL SELECT yr + 1 FROM years WHERE yr < 2015),
invoices AS (
SELECT CAST('2013-06-27' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION
SELECT CAST('2013-07-29' AS date) AS InvoiceDate, 40 AS MarginAmount
UNION
SELECT CAST('2013-10-30' AS date) AS InvoiceDate, 40 AS MarginAmount
)
-- End data setup, real work begins here
SELECT * FROM
(
SELECT
months.mon, years.yr, COALESCE(SUM(inv.MarginAmount), 0) AS MarginAmount
FROM
months
CROSS JOIN years
LEFT OUTER JOIN invoices inv ON ( (YEAR(inv.InvoiceDate) = years.yr) AND (MONTH(inv.InvoiceDate) = months.mon) )
GROUP BY
months.mon, years.yr
) AS source
PIVOT
(
MAX(MarginAmount)
FOR yr in ([2011], [2012], [2013], [2014], [2015])
)
AS pvt
ORDER BY mon
I was wondering how I could change two things:
Replace the numbers 1 - 11 with the names of the months of the year and
Create a line at the bottom of the table summarizing the information above it, where the mon column would have the word 'Total'
Any help would be greatly appreciated
e.g The sum of all sales in 2012 would be displayed at the bottom of the 2012 column
Question 1. Replace numbers
To replace the numbers, you can for instance change this:
months AS (SELECT 1 AS mon UNION ALL SELECT mon + 1 FROM months WHERE mon < 12)
to
months AS (SELECT 1 AS mon, 'Jan' name UNION ALL SELECT mon + 1, months.name FROM months WHERE mon < 12)
Question 2. Grand totals
To create a bottom line with totals you can either use grouping sets (your query seems to be SQL Server, don't know whether SQL Server supports that, please specify):
group
by grouping sets
( ()
, (full list)
)
or add a union to the query:
with myresults as (the whole thing)
select 1 ordering
, myresults.columns-minus-total
, myresults.something subtotal
from myresults
union all
select 2 ordering
, myresults.columns-minus-total
, sum(something) grandtotal
from myresults
order
by 1
, ...other...
Complete example using Microsoft SQL Server 2008 R2
Original code was prettified and without dependencies on tables:
with months as
( select 1 as mon
, 'Jan' monname
union all
select 2
, 'Feb'
union all
select 3
, 'Mar'
union all
select 4
, 'Apr'
union all
select 5
, 'May'
union all
select 6
, 'Jun'
union all
select 7
, 'Jul'
union all
select 8
, 'Aug'
union all
select 9
, 'Sep'
union all
select 10
, 'Oct'
union all
select 11
, 'Nov'
union all
select 12
, 'Dec'
)
, years as
( select 2011 as yr
union all
select 2012
union all
select 2013
union all
select 2014
)
, invoices as
( select cast('2013-06-27' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-07-29' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-10-30' as date) as invoicedate
, 40 as marginamount
)
select *
from ( select months.mon
, years.yr
, coalesce(sum(inv.marginamount), 0) as marginamount
from months
cross
join years
left
outer
join invoices inv
on year(inv.invoicedate) = years.yr
and month(inv.invoicedate) = months.mon
group
by months.mon
, years.yr
) source
pivot ( max(marginamount)
for yr
in ( [2011], [2012], [2013], [2014], [2015]
)
) pvt
order
by mon
Adding the text and grand totals leads to:
with months as
( select 1 as mon
, 'Jan' monname
union all
select 2
, 'Feb'
union all
select 3
, 'Mar'
union all
select 4
, 'Apr'
union all
select 5
, 'May'
union all
select 6
, 'Jun'
union all
select 7
, 'Jul'
union all
select 8
, 'Aug'
union all
select 9
, 'Sep'
union all
select 10
, 'Oct'
union all
select 11
, 'Nov'
union all
select 12
, 'Dec'
)
, years as
( select 2011 as yr
union all
select 2012
union all
select 2013
union all
select 2014
)
, invoices as
( select cast('2013-06-27' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-07-29' as date) as invoicedate
, 40 as marginamount
union
select cast('2013-10-30' as date) as invoicedate
, 40 as marginamount
)
select case
when mon is null
then 'Total'
else cast(mon as varchar)
end
, monname
, [2011]
, [2012]
, [2013]
, [2014]
, [2015]
from ( select months.mon
, months.monname
, years.yr
, coalesce(sum(inv.marginamount), 0) as marginamount
from months
cross
join years
left
outer
join invoices inv
on year(inv.invoicedate) = years.yr
and month(inv.invoicedate) = months.mon
group
by grouping sets
( (months.mon, months.monname, years.yr)
, (years.yr)
)
) source
pivot ( max(marginamount)
for yr
in ( [2011], [2012], [2013], [2014], [2015]
)
) pvt
order
by coalesce(mon, 100)