Using SSRS 2016 and SQL 2017 Report Builder
I have a dataset like the following. It has event dates and attendance:
Event_Date Attendance
1/1/2016 1
2/1/2016 2
3/1/2016 3
4/1/2016 4
5/1/2016 5
6/1/2016 6
7/1/2016 7
8/1/2016 8
9/1/2016 9
10/1/2016 10
11/1/2016 11
12/1/2016 12
1/1/2017 5
2/1/2017 6
3/1/2017 7
4/1/2017 8
5/1/2017 9
6/1/2017 10
7/1/2017 11
8/1/2017 12
9/1/2017 13
10/1/2017 14
11/1/2017 15
12/1/2017 16
I am attempting to create a line chart in an SSRS report where there is a datapoint (Attendance) for each element in the series. I am specifying two series -- Series 1 is the attendance for 2016 and Series 2 is the attendance for 2017. Each series will be on a separate line in the chart. The purpose is to visually compare attendance in 2016 vs 2017.
The date periods are determined dynamically by report parameters when the report is run for one series and by variables calculated from the report parameters for the other series.
In the line chart I have defined:
Values are Attendance
Category Groups are Event_Date (with a filter to select events in 2017)
Series Groups are Event_Date (with a filter to select events in 2016)
PROBLEM
When I run the report, the graph renders but has no data (lines).
If I remove the Series Group (events in 2016), the graph renders correctly with only the data line for 2017.
I've been working on this for quite a while and I am stalled trying to figure out what is going on.
Does anyone have any ideas as to why both series are not being graphed and how to fix it?
Many Thanks!
Note: The solution is simple, don't be put off by the length of the reply ! :)
You'll need to make a few simple changes to your dataset query..
Here's a sample query I used to replicate you data.
DECLARE #t TABLE (Event_Date date, Attendance int)
INSERT INTO #t
VALUES
('1/1/2016', 1),
('2/1/2016', 2),
('3/1/2016', 3),
('4/1/2016', 4),
('5/1/2016', 5),
('6/1/2016', 6),
('7/1/2016', 7),
('8/1/2016', 8),
('9/1/2016', 9),
('10/1/2016', 10),
('11/1/2016', 11),
('12/1/2016', 12),
('1/1/2017', 5),
('2/1/2017', 6),
('3/1/2017', 7),
('4/1/2017', 8),
('5/1/2017', 9),
('6/1/2017', 10),
('7/1/2017', 11),
('8/1/2017', 12),
('9/1/2017', 13),
('10/1/2017', 14),
('11/1/2017', 15),
('12/1/2017', 16)
select Event_Date, format(Event_Date, 'dd/MM') as DayMonth, year(Event_date) as Yr, Attendance from #t
Notice in the final select (the bit you actually need) I've added a year column Yr and a day/month column DayMonth. With your dataset as it was, even if you split by year the x axis would still represent the date so the you two lines would have been next to each other rather than one on top of the other which is what I expect you want....
The result of the dataset gives us something like...
Event_Date DayMonth Yr Attendance
2016-01-01 01/01 2016 1
2016-02-01 02/01 2016 2
.....
.....
2017-01-01 01/01 2017 5
.....
.....
And so on..
Now, add a new line chart and drop Attendance into Values; DayMonth into Category Groups and Yr into Series Groups.
Your chart design should look something like this...
That's it!
When we run the report we get this...
Thanks so much for the help. It pushed me in the right direction so that I could make things work for the situation.
I made some changes to the query so that I could align all the data on top of each other by a yearly event number.
Here is the query:
select
ROW_NUMBER() over (PARTITION BY year([dbo].[#temp_table_4].[event_start_date]) ORDER BY [dbo].[#temp_table_4].[event_start_date]) as yearly_event_number
,format ([dbo].[#temp_table_4].[event_start_date],'d') as event_start_date
,format([dbo].[#temp_table_4].[event_start_date],'MM/dd') as MonthDay
,year([dbo].[#temp_table_4].[event_start_date]) as Year
, Count (*) as [Total Attended]
from
[dbo].[#temp_table_4]
Group by [event_start_date]
order by
[dbo].[#temp_table_4].[event_start_date]
The main change was that I needed to number each event that happened each year beginning with 1 and ending with 'n' (the last event of the year). I needed to do that because the events don't happen on the same date each year (they actually happen each Wednesday which is not the same date each year).
To account for this, I added the following SQL clause:
ROW_NUMBER() over (PARTITION BY year([dbo].[#temp_table_4].[event_start_date]) ORDER BY [dbo].[#temp_table_4].[event_start_date]) as yearly_event_number
In the chart, I assigned Total_Attendance to Values, yearly_event_number to Category Groups and Year to Series Groups. I also added a tool tip that showed the event date so that you can hover over any point and show the event date.
Related
I'm making a graph in SSRS which will highlight the sales for each week from a specific week, and from 52 week up to that date.
For this I have created the following data set in SSRS:
WITH SET LAST52WEEKS AS
{
STRTOMEMBER("[Dim Date].[Week].&[2017]&[1]&[1]&[4]").Lag(52):
STRTOMEMBER("[Dim Date].[Week].&[2017]&[1]&[1]&[4]")
}
Select {[Measures].[Quantity]} ON 0,
{Last52Weeks} ON 1
FROM (
Select {
[Dim Store2].[Store Key].&[1024]
} on columns
from [DSV_FactStoreSales 1]
)
which works as intended, and have an output for week 13 through 4 with each week having a weekly sales Quantity>400 (except for one week with Quantity (null).
However, when I add this data as the Y-axis in a graph in SSRS along with Weeks attribute as the X-axis, only four rows are returned. The rows returned are for the weeks
1,19,3,40
All other values are blank in the graph. Does anyone have any idea as to why this may occur?
Regards,
Cenderze
EDIT updated x-axis from using Interval value = 1
When I changed the Interval value under Horizontal Axis Properties I now get the following values for the x-axis:
1, 13, 14,[...],19, 2, 20, 21, 22, 23, [...], 29, 3, 30, 31, 32,[...],39, 4, 41, 42,[...], 53
where I have bolded the results which seem odd. Im guessing these values are the quarters? I am however using Weeks as my Grouping variable.
EDIT
Following Mike Honey I figured that:
WITH SET LAST52WEEKS AS
{STRTOMEMBER("[Dim Date].[Date].&[1]&[2017-01-29]").Parent.Lag(52)
:
STRTOMEMBER("[Dim Date].[Date].&[1]&[2017-01-29]").parent}
Select {[Measures].[Quantity]} ON 0,
{Last52Weeks} ON 1
FROM (
Select {
[Dim Store2].[Store Key].&[1024]
} on columns
from [DSV_FactStoreSales 1])
ought to work, but it simply returned that Quantity was (null). Why isn't this equivalent to the other Query I wrote, but based off of Date rather than week?
EDIT
I also noted that the graph I am creating has week 52 to the utmost right, whereas it is supposed to have week 4 at the utmost right.
EDIT
EDIT
Edited the Query to become:
WITH SET LAST52WEEKS AS
{STRTOMEMBER("[Dim Date].[Hierarchy].&[2017 W4]").Lag(52):STRTOMEMBER("[Dim Date].[Hierarchy].&[2017 W4]")}
Select {[Measures].[Quantity]} ON 0,
{(Last52Weeks,[Dim Store2].[Store Name].Allmembers)} ON 1
from [DSV_FactStoreSales 1]
where Hierarchy is an Attribute Hierarchy with the values 2010 W1,...., 2018 W52.
But this yields me an output:
2016 W40 Store1 300
2016 W40 Store2 400
...
2017 W39 Store1 400
where I would expect the output to be:
2016 W4 Store1 300
2016 W4 Store2 400
...
2017 W4 Store1 400
Any ideas? It is just an hierarchy with one attribute, Week Name (I've tried the Query with both using [Dim Date].[Hierarchy].[Week Name].&[2017 W4] and [Dim date].[Hierarchy].&[2017 W4], both with the same output.
EDIT (very close now!)
There are two issues I can see with your current chart. One is that your week numbers are being treated as text, which is why the ordering has sequences like 19, 2, 20. The other is that it isn't distinguishing where the week numbers for one year ends and another year starts.
I'm not familiar with mdx. I'm hoping you're able to make a simple dataset that is purely a list of sales with dates. For my solution, I used an Oracle query like:
SELECT date SALEDATE, ID FROM sales
WHERE date BETWEEN '28-MAR-2016' AND '28-JAN-2017'
With a new chart, use [Count(ID)] for the values. It then needs two category groups, first one for the year and then one for the week number. You can use expressions to get these from a date field. For the first category group, set Group on: and Label as
=DatePart(DateInterval.Year, Fields!SALEDATE.Value)
and for the second, set Group on: and Label as
=DatePart(DateInterval.WeekOfYear, Fields!SALEDATE.Value)
To then hide the columns with under 400 sales, right-click the second category group (the weeks one) and add a filter: [Count(ID)] (integer) > 400.
Even if your dataset is different from the raw data approach I'm using, hopefully this will steer you in the right direction.
Right click on the x-axis and choose "Horizontal Axis Properties". Under Axis Options change the Interval value from Auto to 1.
I want to achieve output using mysql query as described in the screen shot.
in the screen shot, its showing amounts for last 12 months.
if I am running it in Jan 2016, it should show column names from Feb-15 to Jan-16.
Any ideas, how can this be achieved?
CREATE TABLE Months (
mo INT );
INSERT INTO Months VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11);
SELECT DATE_FORMAT(DATE(CONCAT(LEFT(NOW(), 7), '-15')
- INTERVAL mo MONTH),
"%b-%y") AS MmmYY
FROM Months ORDER BY mo DESC;
That should give you the headings you want. Then to do the pivoting, see
http://mysql.rjweb.org/doc.php/pivot
I have a dataset which looks like this
ProjectName MonthsThisYear CompletionDate
ProjectA 5 5/1/2013
ProjectB 7 7/15/2013
ProjectC 10 10/21/2013
I want to bar plot a graph where Y axis is project Name and X axis is January 2013, February 2013 ... December 2013.
Now the bar against projectA must be 5 units long, ProjectB is 7 units long and the bar for Project C should be 10 units long.
so that people can see that ProjectA is completed in May, ProjectB is completed in July and project C in October.
How can I plot this graph?
currently I can plot this correctly... but the X-Asix has 0, 2, 4, 6, 8, 10, 12 on it rather than month names.
I am on SSRS 2008 R2.
This is what I see right now
I just want to see month names and year on X axis.
Maybe some more question detail would be useful, but here's one way that works with your data:
The main issue we're facing is that typically a date is the category, but in this case it's actually the Data value, which gives us less control over the labels compared to a category group.
First, set up a chart with a Category Group based on ProjectName, and a Data expression like:
=DateSerial(Year(Fields!CompletionDate.Value), Month(Fields!CompletionDate.Value), 1)
i.e. the first of the month of each CompletionDate value, otherwise your bars will be between months.
Next, we need to sort out the X axis:
In my example I set Minimum to:
=DateAdd(DateInterval.Month
, -1
, DateSerial(Year(Min(Fields!CompletionDate.Value)), 1, 1))
i.e. December for the last year. Set Maximum to:
=DateSerial(Year(Max(Fields!CompletionDate.Value)), 12, 31)
i.e. the end of the year.
Set Interval to 1 and Interval Type to Months.
Format the X Axis to MMM yyyy.
Looks OK:
If you can actually add a Year column with a value 2013 or whatever, pretty much all of the expressions above can be simplified. For example, I've ignored MonthsThisYear, but if you have a Year column you can build the start of the month value based on MonthsThisYear and Year.
I am currently trying to summarise some data tables into a report. Each record in the table consists of a date range, something like this:
StartDate EndDate
--------------------
13/04/13 15/04/13
17/04/13 24/04/13
28/04/13 03/05/13
05/05/13 10/05/13
Assuming the date ranges signify something like days of leave, I want to be able to calculate the total amount of days of leave per month. I came across the DatePart function which seems to work apart from one edge case: when the date range crosses a month boundary. Since the DatePart function returns the month for one given date, I am no longer able to use that to determine the amount of days of leave for that edge case record (in the example above it is record 3), since it applies to two separate months.
Ideally I want my final table to look like:
Month #OfDays
--------------------
4 11 (1st record - 2, 2nd record - 7, 3rd record - 2)
5 8 (3rd record - 3, 4th record - 5)
I've considered some messy options, such as populating a temporary table having each record signifying a different day and then doing a query on that, but I am not sure how this ties in with a report. Right now my report record source is the (incorrect) query, is it possible to have a record source as a VBA function that returns a recordsource?
Another thing I thought was to possibly to have an initial query that splits up any edge cases into two seperate records, where the date range only covers one month, and then use that for my final grouping query. Is that even possible?
I feel there may be a much simpler solution to this problem yet I can't see it.
If anyone has any ideas it would be much appreciated!
To accomplish your task using Access queries you will need to create a table named [Numbers] with a single Number (Long Integer) column named [n] containing the numbers 1, 2, 3, ... up to the highest year you expect to be working with. I created mine as follows
n
----
1
2
3
...
2499
2500
You'll also need to paste the following VBA function into an Access Module
Public Function IsValidDayOfYear(YearValue As Long, DayValue As Long) As Boolean
Dim IsLeapYear As Boolean
If (YearValue Mod 400) = 0 Then
IsLeapYear = True
ElseIf (YearValue Mod 100) = 0 Then
IsLeapYear = False
ElseIf (YearValue Mod 4) = 0 Then
IsLeapYear = True
Else
IsLeapYear = False
End If
IsValidDayOfYear = (DayValue <= IIf(IsLeapYear, 366, 365))
End Function
Let's assume that your source table is called [DateRanges]. We'll start by creating a query that generates every day of the year for each year represented in the source table. The trick here is that DateSerial() "rolls over" month boundaries, so
DateSerial(2013, 1, 32) = #2013-02-01#
and
DateSerial(2013, 1, 234) = #2013-08-22#
SELECT DateSerial(yr.n, 1, dy.n) AS [Date]
FROM Numbers yr, Numbers dy
WHERE
(
yr.n
BETWEEN (SELECT MIN(DatePart("yyyy", DateRanges.StartDate)) FROM DateRanges)
AND (SELECT MAX(DatePart("yyyy", DateRanges.EndDate)) FROM DateRanges)
)
AND (dy.n < 367) AND IsValidDayOfYear(yr.n, dy.n)
For your sample data, that query returns all days in 2013.
Let's save that query as [AllDays]. Now we can use it to extract the individual days for each date range (omitting StartDate so the final counts match yours in the question)
SELECT [Date] FROM AllDays
WHERE EXISTS
(
SELECT * FROM DateRanges
WHERE AllDays.[Date] BETWEEN DateAdd("d", 1, DateRanges.StartDate) AND DateRanges.EndDate
)
That returns the individual days corresponding to each range, i.e.,
Date
----------
2013-04-14
2013-04-15
2013-04-18
2013-04-19
2013-04-20
2013-04-21
2013-04-22
2013-04-23
2013-04-24
2013-04-29
2013-04-30
2013-05-01
2013-05-02
2013-05-03
2013-05-06
2013-05-07
2013-05-08
2013-05-09
2013-05-10
We can save that query as [RangeDays] and then use it to calculate our counts by month...
SELECT DatePart("m", [Date]) AS [Month], COUNT(*) AS NumOfDays
FROM RangeDays
GROUP BY DatePart("m", [Date])
...returning
Month NumOfDays
----- ---------
4 11
5 8
I have a table like this:
ID month year content
1 4 2013 xxxxx
2 5 2013 yyyyy
3 6 2013 zzzzz
4 8 2014 fffff
I want to query it based on a year and month range.
I have query like this:
SELECT * FROM UPP
WHERE ( month = '4' AND year = '2013' )
AND ( month = '6' AND year = '2013' )
That query runs but returns no result. Can anyone help me for fix this query?
NB: The month and year columns are integers.
Why not use the correct data type?
Failing that:
SELECT * FROM UPP WHERE (year=2013) AND (month BETWEEN 4 AND 6);
Would be the easiest path to this particular answer.
EDIT
SQL Fiddle for reference.
There will never be any rows where both month=4 and month=6 which is what your query is asking for. Adding brackets like that will not alter the AND behaviour as you seem to want them to so you are asking for WHERE year=2013 AND month=4 AND month=6.
There are a number of ways you could ask for what you seem to be wanting, for instance:
WHERE (year=2013 AND month=4) OR (year=2013 AND month=6)
or
WHERE year=2013 AND (month=4 OR month=6)
or
WHERE year=2013 AND month IN (4,6)
If you want the full range (the full quarter, months 4, 5, and 6 not just months 4 and 6 then swasheck's suggestion is probably the clearest way to go, though this will fall down if the date range straddles a boundary between years. If you need to do fully flexible ranged queries ("the six months to February 2013" and so forth) then you might want to rethink the table structure to more easily/efficiently support that.