How to order months between two years in SSRS - reporting-services

I have the following table in SQL:
UniqueUsers YEAR MONTH MONTH2
NULL NULL January 1
NULL NULL February 2
NULL NULL July 7
NULL NULL August 8
NULL NULL September 9
NULL NULL October 10
NULL NULL November 11
NULL NULL December 12
1 2016 March 3
2 2016 April 4
2 2016 May 5
1 2016 June 6
In SSRS I have a table grouped by Month with 4 parameters: 1 for Year1 and 1 for Month1; 1 for Year2 and 1 for Month2.
For example, if I select Year1 = 2015 and Month1 = November and December and Year2 = 2016 and Month2 = January and February I need to show the months like this even if the results have NULL values:
Nov Dec Jan Feb Mar Apr May Jun Jul Aug Sep Oct
This is the query than I use:
SELECT *
FROM
(
SELECT
[QUARTER]
,[CARRIER]
,[PLANGROUP]
,[UniqueUsers]
,[YEAR]
,A.[MONTH]
,A.[MONTH2]
FROM [ReportUnit].[dbo].[Month_List] A
LEFT JOIN
(SELECT
[YEAR]
,[MONTH2]
,[CARRIER]
,[PLANGROUP]
,[QUARTER]
,COUNT(DISTINCT [CONTRACT_NUM]) AS [UniqueUsers]
FROM
(
SELECT *
FROM
(
SELECT
MIN([YEAR]) AS [YEAR]
,MIN([MONTH2]) AS [MONTH2]
,DATENAME(MONTH, DATEADD(MONTH, MIN([MONTH2])-1, CAST('2017-01-01' AS datetime))) AS [MONTH]
,[CARRIER]
,[PLANGROUP]
,MIN([QUARTER]) AS [QUARTER]
,[CONTRACT_NUM]
FROM MyTable
WHERE
[YEAR] = #YEAR1
AND [PLANGROUP] IN (#ACCOUNT)
GROUP BY [PLANGROUP],[CARRIER],[CONTRACT_NUM]
) Q1
WHERE
[MONTH] IN (#MONTH1) --THIS IS MONTH NAME PARAMETER IN SSRS
--[MONTH2] IN (11,12)
UNION ALL
SELECT *
FROM
(
SELECT
MIN([YEAR]) AS [YEAR]
,MIN([MONTH2]) AS [MONTH2]
,DATENAME(MONTH, DATEADD(MONTH, MIN([MONTH2])-1, CAST('2017-01-01' AS datetime))) AS [MONTH]
,[CARRIER]
,[PLANGROUP]
,MIN([QUARTER]) AS [QUARTER]
,[CONTRACT_NUM]
FROM MyTable
WHERE
[YEAR] = #YEAR2
AND [PLANGROUP] IN (#ACCOUNT)
GROUP BY [PLANGROUP],[CARRIER],[CONTRACT_NUM]
) Q1
WHERE
[MONTH] IN (#MONTH2) --THIS IS MONTH NAME PARAMETER IN SSRS
--[MONTH2] IN (1,2,3,4,5,6,7,8,9,10)
) Q1
GROUP BY [YEAR],[MONTH2],[PLANGROUP],[CARRIER],[QUARTER]
) B ON A.MONTH2 = B.MONTH2
) Q4
ORDER BY [PLANGROUP], [YEAR], [MONTH2], [MONTH]

The best way to handle these kind of things is create a date table. How detailed that is, is down to your requirements. In your case you may only need months and years, although if you data is more detailed you may need all dates. You can then use this table and left join your main data to it.
The other option is to build a temp table in your dataset with your months and years in it.
I didn't quite understand what parameters you are passing so I'll just have a guess, hopefully this will give you enough to go on anyway. This assumes you are only ever working with data from no more than 2 years, if not then you are probably better to go down the permanent date table route...
So, if you pass in 4 parameters to your dataset query as 2015; 11; 2016; 10 (Nov'15 to Oct'16)
The your dataset query would look something like.
/* uncomment for testing on SSMS only
DECLARE #Year1 int = 2015
DECLARE #Year2 int = 2016
DECLARE #Month1 int = 11
DECLARE #Month2 int = 10
*/
/*Create temp Dates Table*/
DECLARE #d TABLE([Year] int, [Month] int)
INSERT INTO #d
SELECT #Year1, 1 UNION
SELECT #Year1, 2 UNION
SELECT #Year1, 3 UNION
SELECT #Year1, 4 UNION
SELECT #Year1, 5 UNION
SELECT #Year1, 6 UNION
SELECT #Year1, 7 UNION
SELECT #Year1, 8 UNION
SELECT #Year1, 9 UNION
SELECT #Year1, 10 UNION
SELECT #Year1, 11 UNION
SELECT #Year1, 12 UNION
SELECT #Year2, 1 UNION
SELECT #Year2, 2 UNION
SELECT #Year2, 3 UNION
SELECT #Year2, 4 UNION
SELECT #Year2, 5 UNION
SELECT #Year2, 6 UNION
SELECT #Year2, 7 UNION
SELECT #Year2, 8 UNION
SELECT #Year2, 9 UNION
SELECT #Year2, 10 UNION
SELECT #Year2, 11 UNION
SELECT #Year2, 12
SELECT d.[Year], d.[Month], t.myColumns
FROM #d d
LEFT JOIN myTable t on d.[Year] = t.[Year] and d.[Month] = t.[Month]
WHERE
((t.[Year] *100) + t.[Month]) between (#Year1 *100 + #Month1) and (#Year2 *100 + #Month2)
ORDER by d.[Year], d.[Month]

This is the query than I use:
SELECT *
FROM
(
SELECT
[QUARTER]
,[CARRIER]
,[PLANGROUP]
,[UniqueUsers]
,[YEAR]
,A.[MONTH]
,A.[MONTH2]
FROM [ReportUnit].[dbo].[Month_List] A
LEFT JOIN
(SELECT
[YEAR]
,[MONTH2]
,[CARRIER]
,[PLANGROUP]
,[QUARTER]
,COUNT(DISTINCT [CONTRACT_NUM]) AS [UniqueUsers]
FROM
(
SELECT *
FROM
(
SELECT
MIN([YEAR]) AS [YEAR]
,MIN([MONTH2]) AS [MONTH2]
,DATENAME(MONTH, DATEADD(MONTH, MIN([MONTH2])-1, CAST('2017-01-01' AS datetime))) AS [MONTH]
,[CARRIER]
,[PLANGROUP]
,MIN([QUARTER]) AS [QUARTER]
,[CONTRACT_NUM]
FROM MyTable
WHERE
[YEAR] = #YEAR1
AND [PLANGROUP] IN (#ACCOUNT)
GROUP BY [PLANGROUP],[CARRIER],[CONTRACT_NUM]
) Q1
WHERE
[MONTH] IN (#MONTH1) --THIS IS MONTH NAME PARAMETER IN SSRS
--[MONTH2] IN (11,12)
UNION ALL
SELECT *
FROM
(
SELECT
MIN([YEAR]) AS [YEAR]
,MIN([MONTH2]) AS [MONTH2]
,DATENAME(MONTH, DATEADD(MONTH, MIN([MONTH2])-1, CAST('2017-01-01' AS datetime))) AS [MONTH]
,[CARRIER]
,[PLANGROUP]
,MIN([QUARTER]) AS [QUARTER]
,[CONTRACT_NUM]
FROM MyTable
WHERE
[YEAR] = #YEAR2
AND [PLANGROUP] IN (#ACCOUNT)
GROUP BY [PLANGROUP],[CARRIER],[CONTRACT_NUM]
) Q1
WHERE
[MONTH] IN (#MONTH2) --THIS IS MONTH NAME PARAMETER IN SSRS
--[MONTH2] IN (1,2,3,4,5,6,7,8,9,10)
) Q1
GROUP BY [YEAR],[MONTH2],[PLANGROUP],[CARRIER],[QUARTER]
) B ON A.MONTH2 = B.MONTH2
) Q4
ORDER BY [PLANGROUP], [YEAR], [MONTH2], [MONTH]
And I don`t know how I can join it in your temp Table

Related

How to fetch data week wise along side month and year in single query

I have this following which fetches the data Month and Year wise
SELECT
y.year,
m.month,
COALESCE(SUM(o.totalsale), 0) AS totalsale
FROM
(SELECT 2017 AS year UNION SELECT 2018 UNION SELECT 2019) y
CROSS JOIN
(SELECT 1 AS month UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6 UNION
SELECT 7 UNION SELECT 8 UNION SELECT UNION SELECT 10 UNION SELECT 11 UNION SELECT 12) m
LEFT JOIN order o
ON y.year = YEAR(FROM_UNIXTIME(o.time)) AND
m.month = MONTH(FROM_UNIXTIME(o.time)) AND
o.time BETWEEN 1561953600 AND 1577854740
WHERE
d.year = 2019 OR -- display all of 2019
(d.year = 2018 AND m.month BETWEEN 6 AND 12) -- and second half 2018
GROUP BY
y.year,
m.month;
I also want to fetch data Week wise within this query.

SQL Join data count from another tables

I have database
From tabel userlist
NO NAMA DATE
1 THIS 2019-01-17 18:40:45
2 IS 2019-01-17 18:40:45
3 NAME 2019-02-17 18:40:45
From tabel usertext
ID TEXT CREATE
1 THIS 2019-01-18 18:40:45
2 IS 2019-02-21 18:40:45
3 TEXT 2019-03-19 18:40:45
how to return like this with sql query
Month Name Text
Jan 2 1
Feb 1 1
Mar 0 1
i already try this
SELECT MONTHNAME(userlist.date) as Month, COUNT(userlist.no) as name, COUNT(usertext.id) as text FROM userlist, usertext WHERE MONTH(userlist.date) < 12 AND YEAR(userlist.date) = YEAR(CURRENT_TIMESTAMP) GROUP BY MONTHNAME(date)
and return like this
Month Name Text
Jan 1 1
Feb 1 1
Mar 1 1
Union, then aggregate.
SELECT Month, SUM(usr) as Name, SUM(txt) as Text
FROM
(
SELECT MONTH(t.date) AS monthnum, MONTHNAME(t.date) AS Month, 1 AS usr, 0 AS txt
FROM userlist t
WHERE YEAR(t.date) = YEAR(CURRENT_TIMESTAMP)
AND MONTH(t.date) < 12
UNION ALL
SELECT MONTH(t.create) AS monthnum, MONTHNAME(t.create) AS Month, 0 AS usr, 1 AS txt
FROM usertext t
WHERE YEAR(t.create) = YEAR(CURRENT_TIMESTAMP)
AND MONTH(t.create) < 12
) q
GROUP BY monthnum, Month
ORDER BY monthnum
And below a little piece of sql that generates 12 months. It could be an extra UNION ALL in the inner query, to fill gaps for the missing months.
select n as monthnum, monthname(100*n+1) as month, 0 as usr, 0 as txt
from (
select 1 as n 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 union all select 10 union all select 11 union all select 12
) q
You could try joining the subquery for count
select t1.my_month month, t2.count_name, t3.count_text
from(
select month(create ) my_month
from userlist
union
select month(create)
from usertext
) t1
left join (
select month(create) month, count(*) count_name
from userlist
group by month(create)
) t2 on t2.month = t1.my_month
left join (
select month(create) month, count(*) count_text
from usertext
group by month(create)
) t3 on t3.month = t1.my_month

How to add month name with 0 total if data not exist in mysql?

I need to fetch data of the user's from created_date to till current data by month name and year with each month's total price.
Try 1:
SELECT MONTHNAME(start_time) month, YEAR(start_time) year, SUM(price) total
FROM table t1
WHERE t1.id= 33
GROUP BY YEAR(start_time), MONTH(start_time);
Output:
month year total
July 2019 360
September 2019 2160
October 2019 360
Expected output:
All month name and total will be 0 if data not exist.
month year total
Jan 2018 0
Feb 2018 0
...
Dec 2018 0
Jan 2019 0
Feb 2019 0
Mar 2019 0
Apr 2019 0
May 2019 0
Jun 2019 0
July 2019 360
Aug 2019 0
Sep 2019 2160
Oct 2019 360
Nov 2019 0
Dec 2019 0
After some RND I found one way and I have also tried that but now works.
Try 2:
SELECT IFNULL(SUM(ri.price),0) AS total, m.month
FROM (
SELECT 'Jan' AS MONTH
UNION SELECT 'Feb' AS MONTH
UNION SELECT 'Mar' AS MONTH
UNION SELECT 'Apr' AS MONTH
UNION SELECT 'May' AS MONTH
UNION SELECT 'Jun' AS MONTH
UNION SELECT 'Jul' AS MONTH
UNION SELECT 'Aug' AS MONTH
UNION SELECT 'Sep' AS MONTH
UNION SELECT 'Oct' AS MONTH
UNION SELECT 'Nov' AS MONTH
UNION SELECT 'Dec' AS MONTH
) AS m
LEFT JOIN table_u pu
ON MONTH(STR_TO_DATE(CONCAT(pu.created_date, '2019'),'%M %Y')) = MONTH(pu.created_date)
AND YEAR(pu.created_date) = '2019'
LEFT JOIN table ri
ON ri.id = pu.id
GROUP BY m.month
ORDER by 1+1;
Here is my refrence link.
Can anyone help me to fix this issue?
Thanks in advance.
Keep using LEFT JOIN (but only once) with a integer generator upto 12 (instead of month names, also easy using within the ORDER BY clause ), since you are able to get the month names by monthname() function. From your second query, I considered the current year. So, use :
SET #year=YEAR(NOW());
SELECT
MONTHNAME(STR_TO_DATE(concat(YEAR(NOW()),',',m.month,',1'),"%Y,%m,%d")) as month,
#year as year , SUM( COALESCE( pu.price, 0) ) as total
FROM (
SELECT rn as month
FROM
(
SELECT #rn := if(#i = #rn, #rn + 1, 1) as rn,
#i := #i+1
FROM information_schema.character_sets
JOIN (SELECT #i := 0, #rn := 0) as q_iter
LIMIT 12
) q
) AS m
LEFT JOIN table_u pu ON MONTH(pu.start_time) = m.month
AND YEAR(pu.start_time) = #year
AND ID = 33
GROUP BY m.month
ORDER by m.month;
Demo 1
Edit ( From the beginning of the year 2018 to the end of the current year ) :
SELECT MONTHNAME(
STR_TO_DATE(
CONCAT(m.year,',',if(mod(m.month,12)=0,12,mod(m.month,12)),',1'),"%Y,%m,%d")
)
as month,
year,
SUM( CASE WHEN YEAR(pu.start_time) = m.year AND MONTH(pu.start_time) = m.month
THEN
COALESCE( pu.price, 0)
ELSE
0
END ) as total
FROM
(
SELECT #i := if( #i = 12 , 1 , #i+1) as month,
#j := #j + 1,
#k:= if( #i = 1 and #j > 12, #k - 1, #k ) as year
FROM information_schema.character_sets
JOIN (SELECT #i := 0, #j := 0, #k:=YEAR(now())) as q_iter
) m
LEFT JOIN table_u pu ON MONTH(pu.start_time) = m.month
AND ID = 33
GROUP BY month, year
HAVING year >= ( SELECT MIN( YEAR(start_time) ) FROM table_u )
ORDER BY year, m.month;
Demo 2
If you have data in your table for all months, but just not for that id, then you can switch to conditional aggregation:
SELECT MONTHNAME(start_time) as month, YEAR(start_time) as year,
SUM(CASE WHEN t1.id = 33 THEN price ELSE 0 END) as total
FROM table t1
GROUP BY YEAR(start_time),MONTHNAME(start_time)
ORDER BY MIN(start_time);
Creating nonexistent year-month pairs by using user variables:
SELECT monthname(str_to_date(concat_ws(',',ym.month,'01,01'),'%m,%d,%y')) month
, ym.year year
, sum(price)
FROM table1 t1
RIGHT JOIN( SELECT #year := if(#month=12, #year+1, #year ) year
, #month := if(#month=12, 1 , #month+1) month
FROM table1
, ( SELECT #startYear := min(start_time)
, #endYear := year(now())
, #month := 12
, #year := min(start_time)-1
FROM table1
) t
WHERE (#year,#month) < (#endYear,12)
) ym
ON ym.year = year(t1.start_time)
AND ym.month = month(t1.start_time)
GROUP BY year(t1.start_time)
, month(t1.start_time)
The ym derived table is to provide year-month pairs starting on min year in table1 upto current year.
The innermost SELECT is for variables initialization.
You can try this:
SELECT to_char(start_time,'month')MONTH,to_char(start_time,'yyyy')YEAR,SUM(price)total
FROM TABLE_NAME
GROUP BY to_char(start_time,'month'),to_char(start_time,'yyyy')
Finally, I got the correct output which I want.
select
DATE_FORMAT(m1, '%M - %Y')
from
(
select
('2013-07-23')
+INTERVAL m MONTH as m1
from
(
select #rownum:=#rownum+1 as m from
(select 1 union select 2 union select 3 union select 4) t1,
(select 1 union select 2 union select 3 union select 4) t2,
(select 1 union select 2 union select 3 union select 4) t3,
(select 1 union select 2 union select 3 union select 4) t4,
(select #rownum:=-1) t0
) d1
) d2
where m1<=NOW()
order by m1

quarter year wise result filteration in sql

I have a table having structure as follows
id cust_id target month year fiscal_ID
1 234 50 4 2013 1
2 234 50 5 2013 1
3 234 50 6 2013 1
4 234 150 7 2013 1
5 234 150 8 2013 1
6 234 150 9 2013 1
I need to get the result as follows
cust_id target quarter year fiscal_ID
234 150/450 Q1/Q2 2013 1
months 4,5,6 in Q1, 7,8,9 in Q2 etc
In order to concatenate the values from the multiple rows together, you will need to implement FOR XML PATH, similar to this:
;with cte as
(
select t.cust_id,
sum(target) target,
d.qtr,
t.year,
t.fiscal_id
from yourtable t
inner join
(
select 4 mth, 'Q1' qtr union all
select 5 mth, 'Q1' qtr union all
select 6 mth, 'Q1' qtr union all
select 7 mth, 'Q2' qtr union all
select 8 mth, 'Q2' qtr union all
select 9 mth, 'Q2'
) d
on t.month = d.mth
group by t.cust_id, d.qtr, t.year, t.fiscal_id
)
select distinct cust_id,
STUFF(
(SELECT ' / ' + cast(c2.target as varchar(10))
FROM cte c2
where c1.cust_id = c1.cust_id
and c1.year = c2.year
and c1.fiscal_id = c2.fiscal_id
FOR XML PATH (''))
, 1, 2, '') AS target,
STUFF(
(SELECT ' / ' + c2.qtr
FROM cte c2
where c1.cust_id = c1.cust_id
and c1.year = c2.year
and c1.fiscal_id = c2.fiscal_id
FOR XML PATH (''))
, 1, 2, '') AS qtr,
year,
fiscal_id
from cte c1;
See SQL Fiddle with Demo

How to get a list of months between two dates in mysql

I hve to get the list of months between two dates in mysql.
For Example:My Input is
From date 23-01-2013
To Date 01-04-2014
Output Should be
Jan 2013,
Feb 2013,
March 2013,
.
.
.
Jan 2014,
Feb 2014,
Mar 2014,
Apr 2014.
SQLFiddle demo
select
DATE_FORMAT(m1, '%b %Y')
from
(
select
('2013-01-23' - INTERVAL DAYOFMONTH('2013-01-23')-1 DAY)
+INTERVAL m MONTH as m1
from
(
select #rownum:=#rownum+1 as m from
(select 1 union select 2 union select 3 union select 4) t1,
(select 1 union select 2 union select 3 union select 4) t2,
(select 1 union select 2 union select 3 union select 4) t3,
(select 1 union select 2 union select 3 union select 4) t4,
(select #rownum:=-1) t0
) d1
) d2
where m1<='2014-04-01'
order by m1
this is a practical solution, it's not so 'elegant' if you wanna see it that way, but it works, and you can make it a function and/or a stored procedure, just with a couple of parameters...
first, we need a table with some records, any table.
we're gonna use this table, just as a row number table. (you'll need as many rows for the same amount of months you wanna display, having a large table is better) >>
SELECT CONCAT(table_schema, '.', table_name) as schema_table, table_rows
FROM information_schema.TABLES
order by 2 desc limit 0,100
this will tell you, the top 100 tables with most records on your instance, i'm using the mysql.help table for this example, by default, this comes with some thousand records, and it's allways there...
set #start_date = '2013-01-23';
set #end_date = '2014-04-01';
set #months = -1;
select DATE_FORMAT(date_range,'%M, %Y') AS result_date from (
select (date_add(#start_date, INTERVAL (#months := #months +1 ) month)) as date_range
from mysql.help_topic a limit 0,1000) a
where a.date_range between #start_date and last_day(#end_date);
explained:
1. set date variales
2. set month value, for adding months
3. select for each row, a date (we add a month and increment the month variable on the same row)
4. filter dates that are between range
5. output formated dates.
this is the final output>>
January, 2013
February, 2013
March, 2013
April, 2013
May, 2013
June, 2013
July, 2013
August, 2013
September, 2013
October, 2013
November, 2013
December, 2013
January, 2014
February, 2014
March, 2014
April, 2014
Try this one:
select aDate from (
select #maxDate - interval (a.a+(10*b.a)+(100*c.a)+(1000*d.a)) day aDate from
(select 0 as a 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) a, /*10 day range*/
(select 0 as a 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) b, /*100 day range*/
(select 0 as a 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) c, /*1000 day range*/
(select 0 as a 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) d, /*10000 day range*/
(select #minDate := '2001-01-01', #maxDate := '2002-02-02') e
) f
where aDate between #minDate and #maxDate
This SQL from the following helped in my MYSQL. You can update the curdate() value as per your need to get the list of dates of any month.
link: (https://www.programmersought.com/article/26156494713/)
SELECT DATE_FORMAT(DATE_SUB(last_day(curdate()), INTERVAL xc-1 day), '%Y-%m-%d') as date
FROM (
SELECT #xi:=#xi+1 as xc from
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) xc1,
(SELECT 1 UNION SELECT 2 UNION SELECT 3 UNION SELECT 4 UNION SELECT 5 UNION SELECT 6) xc2,
(SELECT #xi:=0) xc0
) xcxc) x0 where x0.date >= (select date_add(curdate(),interval-day(curdate())+1 day))