I've a SSRS report which should look like below,
--------------------------------
Year Product Total customers
--------------------------------
2015 prd1 100
prd2 50
prd3 60
2014 prd1 80
prd2 60
prd3 60
Varience
Prd1 20
Prd2 -10
Prd3 0
I've done the year wise grouping and the data mapping. But I'm not sure how to add variance(between 2015-2014) in each row based on the each product of the year
Update:
My dataset looks like this
Year CategoryId CategoryDesc TotalCustomerCount
2013 Prd1 Testproduct 100
2013 Prd2 Testprod2 50
2013 Prd3 Tesrprod3 45
2014 Prd1 Testproduct 80
2014 Prd2 Testprod2 60
You can see that some products may miss out in a year.
Note: The dataset is created from a Dimesional cube and not from SQL queries.
It is kind of hard to tell exactly without knowing what your current dataset looks like.
But I believe that Stanislovas' example will be of little use to you because his example only works if your dataset has a single row for each product, with columns with the total for each year. Which I'm guessing you do not have because you used row grouping to get the above result. If you did, you could've used column-grouping instead of row-grouping to get a better overview.
You have two possibilities:
Replace your current dataset completely with a dataset that has columns for each year value (like in Stanislovas' example). To achieve this kind of dataset you need your query to look like this for example:
SELECT DISTINCT(myTable.Product), t1.Total AS 'Total2014', t2.Total AS 'Total2015'
FROM myTable
JOIN (SELECT Product, SUM(Total) AS Total
FROM myTable
WHERE Year = 2014
GROUP BY Product) as t1 ON t1.Product = myTable.Product
JOIN (SELECT Product, SUM(Total) AS Total
FROM myTable
WHERE Year = 2015
GROUP BY Product) as t2 ON t2.Product = myTabel.Product
This can then be used to make a table that looks like this:
---------------------------------------
| Product | 2014 | 2015 | Variance |
---------------------------------------
| prd1 | 100 | 80 | 20 |
| prd2 | 50 | 60 | -10 |
| prd3 | 60 | 60 | 0 |
...
Or you can add a second datasource that has calculated these differences before sending it to the reporter. Here is an example to help you with your query: https://stackoverflow.com/a/15002915/4579864
If you need any more help, just leave a comment and I'll try and explain furthur. This should at least get you started.
I think the easiest way to handle this requeriment is generating the data from the query using T-SQL. However the output you require can be produced from SSRS using a dataset with the same structure as the dataset you provided in the update.
In order to recreate your scenario I used this dataset.
Year Product CategoryDesc TotalCustomerCount
2013 Prd1 Testproduct 100
2013 Prd2 Testprod2 50
2013 Prd3 Tesrprod3 45
2014 Prd1 Testproduct 80
2014 Prd2 Testprod2 60
My approach is take the minimum and maximum year values (2013 and 2014) and the product in every row and look up the TotalCustomerCount to substract it. This is a step by step guide.
First, create a calculated field in your dataset. Right click the dataset in Report Data pane, call it Year_Product and set this expression in the field source textbox.
=Fields!Year.Value & "-" & Fields!Product.Value
This will produce an additional field called Year_Product which has Year and Product fields concatenated with the - character in middle. In example: 2013-Prd1, 2014-Prd1, 2013-Prd3 etc.
Now create a tablix with this data arrangement:
In the cell highlighted in red use this expression:
=Lookup(Max(Fields!Year.Value,"DataSet13") & "-" &
Fields!Product.Value,Fields!Year_Product.Value,Fields!TotalCustomerCount.Value,"DataSet13")
-
Lookup(Min(Fields!Year.Value,"DataSet13") & "-" &
Fields!Product.Value,Fields!Year_Product.Value,Fields!TotalCustomerCount.Value,"DataSet13")
This will look up the max year and product of the row in the Year_Product field and get the TotalCustomerCount.
Year_Product: 2014-Prd1 and TotalCustomerCount: 80
Year_Product: 2013-Prd1 and TotalCustomerCount 100
The above example produces -20 since 80 - 100 = -20
It will show us repeated products because every product may be present two times. To avoid this it is necessary to sort the tablix by Product, go to tablix properties and set the below sorting option.
Now hide duplicated rows. Go to tablix properties / Row visibility and select Show or hide based on an expression.
Use this expression ton conditionally hide the duplicated products:
=IIF(
Fields!Product.Value=PREVIOUS(Fields!Product.Value),
true,
false
)
Finally if you preview the report you will see something like this (I recreated your both tables.)
Note I am using only one dataset, the same that you provide in your
question.
Hopefully this what you are looking for let me know if you need further help.
Related
Is there a way in SSRS to have an additional row within your row group, to look at a different column group than the rest of the row group
Let's say I have STATES, SALES, MONTH, and BUCKET_MONTH as my dataset fields BUCKET_MONTH is already calculated for me, based off of the MONTH. I want to show something like this:
SAMPLE DATA LIKE THIS FOR FLORIDA (and other months but BUCKET_MONTH only matters for florida let's pretend)
STATE MONTH SALES BUCKET_MONTH
FL JAN 50 FEB
FL FEB 125 FEB
FL MAR 100 MAY
FL APR 0 MAY
FL MAY 100 MAY
SSRS MATRIX MIGHT LOOK LIKE THIS: ?
| 2 groups ?
| MONTH
| BUCKET_MONTH (I can hide this header)
-----------------------------------
1 col group|
STATE | SALES
BUCKET | SALES <-- this row is only visibile for FL which I know how to do
EXPECTED RESULTS WOULD LOOK LIKE THIS
JAN FEB MAR APR MAY JUN JUL
---------------------------------------------------------------------
CA 100 300 150
FL 50 125 100 0 100
FL BUCKET 175 200 <-- BUCKET_MONTH**
MA 0 200 250 50
BUCKET_MONTH in ds shows FEB for the rows with Jan,Feb MONTH, and shows MAY for Mar,Apr, May MONTH
Is there a way to do this in SSRS? Where one of the rows looks at a different column group to establish what column to put the SUM of SALES in?
Much appreciation in advance!
You have to add BUCKET_MONTH as parent column group in your matrix.
Add BUCKET_MONTH in the Column Groups pane, then delete the created row in the matrix selecting Delete groups only option. Now add MONTH as child group in column groups pane.
Add STATE in rows group pane and add a row for bucket total.
Use this expression for BUCKET TOTAL:
=IIF(
Fields!BUCKET_MONTH.Value=Fields!MONTH.Value,
SUM(Fields!SALES.Value,"BUCKET_MONTH"),
Nothing
)
It should produce:
UPDATE: Expression updated taking in account that MONTH and BUCKET_MONTH fields are actually dates.
=IIF(
UCASE(format(Fields!BUCKET_MONTH.Value,"MMMM yy"))=
UCASE(format(Fields!MONTH.Value,"MMMM yy")),
SUM(Fields!SALES.Value,"BUCKET_MONTH"),
Nothing
)
Let me know if this helps.
We have a database for patients that shows the details of their various visits to our office, such as their weight during that visit. I want to generate a report that returns the visit (a row from the table) based on the difference between the date of that visit and the patient's first visit being the largest value possible but not exceeding X number of days.
That's confusing, so let me try an example. Let's say I have the following table called patient_visits:
visit_id | created | patient_id | weight
---------+---------------------+------------+-------
1 | 2006-08-08 09:00:05 | 10 | 180
2 | 2006-08-15 09:01:03 | 10 | 178
3 | 2006-08-22 09:05:43 | 10 | 177
4 | 2006-08-29 08:54:38 | 10 | 176
5 | 2006-09-05 08:57:41 | 10 | 174
6 | 2006-09-12 09:02:15 | 10 | 173
In my query, if I were wanting to run this report for "30 days", I would want to return the row where visit_id = 5, because it's 28 days into the future, and the next row is 35 days into the future, which is too much.
I've tried a variety of things, such as joining the table to itself, or creating a subquery in the WHERE clause to try to return the max value of created WHERE it is equal to or less than created + 30 days, but I seem to be at a loss at this point. As a last resort, I can just pull all of the data into a PHP array and build some logic there, but I'd really rather not.
The bigger picture is this: The database has about 5,000 patients, each with any number of office visits. I want to build the report to tell me what the average wait loss has been for all patients combined when going from their first visit to X days out (that is, X days from each individual patient's first visit, not an arbitrary X-day period). I'm hoping that if I can get the above resolved, I'll be able to work the rest out.
You can get the date of the first and next visit using query like this (Note that this doesn't has correct syntax for date comparing and it is just an schema of the query):
select
first_visits.patient_id,
first_visits.date first_date,
max(next_visit.created) next_date
from (
select patient_id, min(created) as "date"
from patient_visits
group by patient_id
) as first_visits
inner join patient_visits next_visit
on (next_visit.patient_id = first_visits.patient_id
and next_visit.created between first_visits.created and first_visits.created + 30 days)
group by first_visits.patient_id, first_visits.date
So basically you need to find start date using grouping by patient_id and then join patient_visits and find max date that is within the 30 days window.
Then you can join the result to patient_visits to get start and end weights and calculate the loss.
I have been trying to figure this out for a while now and just couldn't find the answer anywhere.
I have a report in SSRS with a column group assigned to "Year", this column expands depending on what parameter the user enters into StartYear. If the user enters "2013" the report will extract all data from 2013 to 2015, this means that there are then 3 columns with the same name ("Cost").
My report looks something like this when entering StartYear as "2013" the value beneath "Year" displays the "Cost" column :
Area | 2013 ("Year") | 2014 ("Year") | 2015 ("Year")
A | 20 | 50 | 25
B | 15 | 65 | 35
C | 40 | 70 | 20
Before the report get built, the reports looks something like this:
Area | [Year]
[Area] | [Cost]
I want to add a column to this report which displays the Average but only for the Year 2015.
This is what I have tried sofar but it brings back the Average for one row and all the year : 20, 50 and 25 instead of 25, 35 and 20:
=Sum(IIF(Fields!Year.Value = 2015, Avg(Fields!Cost.Value), 0))
Any help would be greatly appreciated.
You need an expression like:
=Avg(IIF(Fields!Year.Value = 2015, Fields!Cost.Value, Nothing))
If you are using an IIf expression to get a subset from a DataSet, you must specify Nothing as the False part of the expression, otherwise you just get a bunch of zeroes included in the aggregate, skewing the results.
This assumes the aggregate is running outside any particular Group Scope - you can always add a Scope to the expression to make sure you are checking the entire DataSet:
=Avg(IIF(Fields!Year.Value = 2015, Fields!Cost.Value, Nothing), "DataSet1")
Edit after comment
To expand on the Scope comment above, you can specify the aggregate to run at the Row Group level by adding the Row Group name as a parameter to the expression:
=Avg(IIF(Fields!Year.Value = 2015, Fields!Cost.Value, Nothing), "Area")
Assuming Area is the name of the Row Group.
I am developing an SSRS report with the following dataset. There is a filter for 'Period'. It is a multi-select filter. Data is grouped by 'Account' field. I need to display Total Expense for each group (which was easy). I also need to display 'Budget' on the same group level. The problem is the budget data is redundant - see below.
Say for the first group (Account=100 AND Period=201301), Sum([Budget]) would generate 200, which is not true. I can use the Average function which helps if user selects only one Period from the filter. If they select multiple values (e.g. 201301,201302) then the average will be (100+100+150+150)/4=125, which would be wrong because it has to be 100+150=250. I don't want to average among all rows in the returned dataset.
ID Account Period Expense Budget
1 100 201301 20 100
2 100 201301 30 100
3 100 201302 10 150
4 100 201302 40 150
5 200 ...................
So, how do I write an expression to make this happen?
A dirty workaound would be to eliminate redundant values in the Budget column so I can safely use Sum([Budget]) w/o worrying about duplication. The updated dataset would look like this:
ID Account Period Expense Budget
1 100 201301 20 100
2 100 201301 30 NULL
3 100 201302 10 150
4 100 201302 40 NULL
5 200 ...................
Please advice for either approach. Thank you.
The most elegant way is to use the FIRST() aggregate function.
=FIRST(Fields!Budget.Value, "MyAccountGroupName")
There are some situations where this won't work. Then you need to move the logic to your query as you describe or you can get fancy with embedded code in your report.
I would follow your "dirty workaround" approach. You might possibly be able to achieve the result just inside SSRS with some fancy calculations, but it will be totally obscure.
compliment of the day.
Based on the previous feedback received,
After creating a Ticket sales database in MS Access. I want to use a single form to Query the price of a particular ticket at a particular month and have the price displayed back in the form in a text field or label.
Below are sample tables and used query
CompanyTable
CompID CompName
A Ann
B Bahn
C Can
KK Seven
- --
TicketTable
TicketCode TicketDes
10 Two people
11 Monthly
12 Weekend
14 Daily
TicketPriceTable
ID TicketCode Price ValidFrom
1 10 $35.50 8/1/2010
2 10 $38.50 8/1/2011
3 11 $20.50 8/1/2010
4 11 $25.00 11/1/2011
5 12 $50.50 12/1/2010
6 12 $60.50 1/1/2011
7 14 $15.50 2/1/2010
8 14 $19.00 3/1/2011
9 10 $40.50 4/1/2012
Used query:
SELECT TicketPriceTable.Price
FROM TicketPriceTable
WHERE (((TicketPriceTable.ValidFrom)=[DATE01]) AND ((TicketPriceTable.TicketCode)=[TCODE01]));
In MS Access, a mini boxes pops up to enter the parameters when running the query. How can I use a single form to enter the parameters for [DATE01] and [TCODE01]. and the price displayed in the same form in a textfield (For further calculations).
Such as 'Month' field equals to input to [DATE01] parameter
'Ticket Code' equals to input for [TCODE01] parameter
Textfield equals to output of the query result (Ticket price)
If possible, I would like to use only the Month and Year in this format MM/YYYY.The day is not necessarry. How can I achieve it in MS Access?
If any question, please don't hesitate to ask
Thanks very much for your time and anticipated feedback.
You can refer to the values in the form fields by using expressions like: [Forms]![NameOfTheForm]![NameOfTheField]
Entering up to 300 different types of tickets
Answer to your comment referring to Accessing data from a ticket database, based on months in MS Access)
You can use Cartesian products to create a lot of records. If you select two tables in a query but do not join them, the result is a Cartesian product, which means that every record from one table is combined with every record from the other.
Let's add a new table called MonthTable
MonthNr MonthName
1 January
2 February
3 March
... ...
Now if you combine this table containing 12 records with your TicketTable containing 4 records, you will get a result containing 48 records
SELECT M.MonthNr, M.MonthName, T.TicketCode, T.TicketDes
FROM MonthTable M, TicketTable T
ORDER BY M.MonthNr, T.TicketCode
You get something like this
MonthNr MonthName TicketCode TicketDes
1 January 10 Two people
1 January 11 Monthly
1 January 12 Weekend
1 January 14 Daily
2 February 10 Two people
2 February 11 Monthly
2 February 12 Weekend
2 February 14 Daily
3 March 10 Two people
3 March 11 Monthly
3 March 12 Weekend
3 March 14 Daily
... ... ... ...
You can also get the price actually valid for a ticket type like this
SELECT TicketCode, Price, ActualPeriod AS ValidFrom
FROM (SELECT TicketCode, MAX(ValidFrom) AS ActualPeriod
FROM TicketPriceTable
WHERE ValidFrom <= Date
GROUP BY TicketCode) X
INNER JOIN TicketPriceTable T
ON X.TicketCode = T.TicketCode AND X.ActualPeriod=T.ValidFrom
The WHERE ValidFrom <= Date is in case that you entered future prices.
Here the subquery selects the actually valid period, i.e. the ValidFrom that applies for each TicketCode. If you find sub-selects a bit confusing, you can also store them as query in Access or as view in MySQL and base a subsequent query on them. This has the advantage that you can create them in the query designer.
Consider not creating all your 300 records physically, but just getting them dynamically from a Cartesian product.
I let you put all the pieces together now.
In Access Forms you can set the RecordSource to be a query, not only a table. This can be either the name of a stored query or a SQL statement. This allows you to have controls bound to different tables through this query.
You can also place subforms on the main form that are bound to other tables than the main form.
You can also display the result of an expression in a TextBox by setting the ControlSource to an expression by starting with an equal sign
=DLookUp("Price", "TicketPriceTable", "TicketCode=" & Me!cboTicketCode.Value)
You can set the Format of a TextBox to MM\/yyyy or use the format function
s = Format$(Now, "MM\/yyyy")