Average on group totals i Reporting Services 2012 - reporting-services

I am trying to make an average on group totals in SQL Server Reporting Services 2012 with a tablix.
Seems to be the same problem that this question is struggeling with...however there are no responses: SQL 2005 Reporting Services - Wrong Average Values
My tablix looks like the following:
+-------+---------+-----------+-----------+
| | | Product A | Product B |
+-------+---------+-----------+-----------+
| | Average | ??? | ??? |
| | | | |
| Week1 | | 550 | 175 |
| | Day 1 | 250 | 100 |
| | Day 2 | 200 | 50 |
| | Day 3 | 100 | 25 |
| | | | |
| Week2 | | 600 | 240 |
| | Day 1 | 300 | 200 |
| | Day 2 | | 30 |
| | Day 3 | | 10 |
+-------+---------+-----------+-----------+
The average should only be calculated for the week-totals. I.e. for Product A the average should be (550+600)/2=575.
My formula for average looks like the following:
=Avg(Fields!WeekTotal.Value)
however this gives a wrong result - my guess is that it takes the days into account aswell?
The question gets harder, because sometimes i do not have the Days sale, in which case the WeekTotal will be a prediction
My dataset, which comes from a SQL Server table, contains the following data:
+---------+------+-----+-----------+----------+
| Product | Week | Day | WeekTotal | DayTotal |
+---------+------+-----+-----------+----------+
| A | 1 | 1 | 550 | 250 |
| A | 1 | 2 | 550 | 200 |
| A | 1 | 3 | 550 | 100 |
| B | 1 | 1 | 175 | 100 |
| B | 1 | 2 | 175 | 50 |
| B | 1 | 3 | 175 | 25 |
| A | 2 | 1 | 600 | 300 |
| A | 2 | 2 | 600 | NULL |
| A | 2 | 3 | 600 | NULL |
| … | … | … | … | … |
+---------+------+-----+-----------+----------+
Any help is appreciated!

You can simply sum all the detail values (at day level) then divide by the number of unique weeks. Something like this...
=Sum(Fields!DayTotal.Value)/CountDistinct(Fields!Week.Value)
In your sample CountDistinct(Fields!Week.Value) will return 2
This all assumes you have a simple Matrix as your report design something like this...
The expression is the expression above to calculate the average.
Please note in my sample data I have more detail so I grouped by day as well as week. In your case you don;t need to group by day (but it will still work if you do)
Also, you don't need the week total as you can simply sum the day totals at the week group level.
UPDATE based on OP comments:
As you need to use the actual week totals in your data (which are not always just a sum of the day totals as I thought previously) we will have to edit the dataset and do a bit of the work there.
Below is the code is used to generate your sample dataset.
DECLARE #t TABLE (Product varchar(1), [Week] int, [Day] int, WeekTotal int, DayTotal[int])
INSERT INTO #t
VALUES
('A', 1, 1, 550, 250),
('A', 1, 2, 550, 200),
('A', 1, 3, 550, 100),
('B', 1, 1, 175, 100),
('B', 1, 2, 175, 50),
('B', 1, 3, 175, 25),
('A', 2, 1, 600, 300),
('A', 2, 2, 600, NULL),
('A', 2, 3, 600, NULL)
SELECT
*
, CAST(WeekTotal as float) / COUNT(*) OVER(PARTITION BY Product, [Week]) as WeekTotalAverage
FROM #t
Notice that I now return an extra column WeekTotalAverage (I know, poor name!). What this does is give us an average per product/week of the weektotal, we can then simply replace the daytotal in the previous expression with this field. The dataset output looks like this.
Product Week Day WeekTotal DayTotal WeekTotalAverage
A 1 1 550 250 183.333333333333
A 1 2 550 200 183.333333333333
A 1 3 550 100 183.333333333333
A 2 1 600 300 200
A 2 2 600 NULL 200
A 2 3 600 NULL 200
B 1 1 175 100 58.3333333333333
B 1 2 175 50 58.3333333333333
B 1 3 175 25 58.3333333333333
I've CAST the result of this column to a float or we end up losing fractions of the numbers when the result is recurring. So in this case product B week 1 has three entries so we take the week total (165) and divide by 3 to give us 58.33 recurring.
The report design changes a little too. It now looks like this.
The week total is now just [WeekTotal] (previously it was [SUM(DayTotal)]) and the expression for the Average is now..
=Sum(Fields!WeekTotalAverage.Value) / CountDistinct(Fields!Week.Value)
In the matrix, there are two row groups, the first groups by Week and the second (child group) is grouped by Day. The column group is grouped on Product.

My solution would be to create a second recordset that has only one weekly total entry for every week, and then take the average from that scope rather than the recordset used for the detailed part of the report.

Related

Get a result only when all the conditions are met in my sql where statement

I'm really struggling with this situation.
I have a table made of symptoms and diseases, for each disease I have n symptoms, now, I want that the SQL retrieve the disease id only if all the Symptoms Ids on the where clause met with all the symptoms for one disease.
Let me explain it with an example. And show you what I tried to do.
| 13 | 3 |
| 16 | 3 |
| 17 | 3 |
| 18 | 3 |
| 19 | 3 |
| 20 | 3 |
| 21 | 3 |
| 22 | 3 |
| 23 | 3 |
| 24 | 3 |
| 25 | 3 |
| 26 | 3 |
| 5 | 4 |
| 9 | 4 |
| 28 | 4 |
| 5 | 5 |
| 23 | 5 |
The chart above is a part of this symptoms-disease table (compose), the left column is the symptoms and the right one the diseases.
Let's say I want the disease with the id n° 4, this disease is linked only with 3 symptoms (5, 9, 28), so I imagined that a SQL like
SELECT disease_id
FROM compose
WHERE symptom_id = 5
AND
symptom_id = 9
AND
symptom_id = 28;
but this SQL returns an Empty Set, I don't really understand why, It does not sound hard, but I honestly not seeing what's wrong. Any help is welcome. Thanks
You are on the right track, but you need to aggregate by disease and then express your assertion on the number of diseases:
SELECT disease_id
FROM compose
WHERE symptom_id IN (5, 9, 28)
GROUP BY disease_id
HAVING COUNT(DISTINCT symptom_id) = 3;
If you want to exclusively match 3 and only three symptoms, then we need to rephrase the query a bit:
SELECT disease_id
FROM compose
GROUP BY disease_id
HAVING
SUM(symptom_id = 5) > 0 AND
SUM(symptom_id = 9) > 0 AND
SUM(symptom_id = 28) > 0 AND
SUM(symptom_id NOT IN (5, 9, 28)) = 0;

Count the different dates of each users mysql

I have a table called order_match which contain columns createdby as the buyer, createdAt as the date of transaction, and order_status_Id as the order_status.
If order_status_id is (4, 5, 6, 8) then the transaction are approved, so I want to count every different days of each buyer so I know the gap of each buyer to doing new transaction after the last transaction.
After that, I can determine the max day of the longest transaction gap, and the minimum day, and the average of the buyers on that range to doing transaction
This is the example data of the transaction between 2018-12-01 until 2018-12-04
+-----------+------------+-----------------+
| createdby | createdAt | order_status_id |
+-----------+------------+-----------------+
| A | 2018-12-01 | 4 |
| A | 2018-12-02 | 5 |
| A | 2018-12-04 | 5 |
| B | 2018-12-02 | 5 |
| B | 2018-12-04 | 5 |
| C | 2018-12-03 | 5 |
| C | 2018-12-04 | 6 |
+-----------+------------+-----------------+
From that data, what expected results is :
+-------------------------------+---------+---------------------------------------+
| max day | min day | average day of the transaction |
+-------------------------------+---------+---------------------------------------+
| 2 (the transaction on | 1 | 1,5 (average from each gap |
| buyer "A" ('2018-12-02' to | | day / of the gap transaction held) |
| '2018-12-04) and "B" | | |
| ('2018-12-02' to '2018-12-04) | | |
+-------------------------------+---------+---------------------------------------+
The point is I want to count time lag in days between every two consecutive purchases made by the buyer within the selected time frame. the difference in days also calculates the time lag between the last purchase before the selected time range (if any) and the first purchase in the selected time range.
This is my progress syntax
SELECT
SUM((DATEDIFF(GREATEST(om1.createdAt, '2018-12-18'),
LEAST(om2.createdAt, '2018-12-20')) * -1) + 1)
FROM order_match om1, order_match om2
WHERE om1.createdAt <='2018-12-20'
AND om2.createdAt >= '2018-12-18'
AND om1.order_status_Id IN (4, 5, 6, 8)
GROUP BY om1.createdby;

How to loop table rows and get header - value pair on MySQL

For example I got table like this:
ID | GroupID | Fee | Discount
-----------------------------
1 | 20 | 60 | 15
2 | 21 | 55 | 42
I want to loop each row and get header - value pair like this:
From row 1: GroupID - 20, Fee - 60, Discount - 15
From row 2: GroupID - 21, Fee - 55, Discount - 42
So basically, this is my old table and I want to convert it to the new one. The new one will look like this:
ID | GroupID | Type | Value
-------------------------------
1 | 20 | Fee | 60
2 | 20 | Discount | 15
3 | 21 | Fee | 55
4 | 21 | Discount | 42
SELECT
t.ID,
t.GroupID,
a.Type,
IF(a.Type = 'Fee', Fee, Discount) AS `Value`
FROM t
CROSS JOIN (SELECT 'Fee' AS Type UNION SELECT 'Discount') a
ORDER BY ID, GroupID;
see it working live here

subtract 2 DB rows from each other for each unique partner_ID? MYSQL

I have a MYSQL table where I need to get to subtract values from 2 different rows.
This is my DB table:
Tablename: ext_partnertotals
| Partner_ID | Partnername | Month | Year | Total |
|------------|-------------|-------|------|-------|
| 1 | Partner 1 | 1 | 2018 | 10 |
| 1 | Partner 1 | 2 | 2018 | 12 |
| 2 | Partner 2 | 1 | 2018 | 18 |
| 2 | Partner 2 | 2 | 2018 | 12 |
It should get this with a query:
| Partner_ID | Partnername | up/down |
|------------|-------------|---------|
| 1 | Partner 1 | +2 |
| 2 | Partner 2 | -6 |
I need to get the Subtract value of 2 different months for each Partner.
Every Partner has a tablerow for each month and a value for that month.
Now I need to get If they went up or went down in value since the month before.
Can someone write me a query?
Since you're unable to improve your terrible schema, I recommend you use a (very ugly/hard to maintain and very slow) correlated subquery:
SELECT Partner_ID, Partnername, Year, Month, Total - (
SELECT Total
FROM ext_partnertotals AS prev
WHERE prev.Partner_ID = cur.Partner_ID AND CASE cur.Month
WHEN 1 THEN prev.Year = cur.Year - 1 AND prev.Month = 12
ELSE prev.Year = cur.Year AND prev.Month = cur.Month - 1
END
) AS `up/down` FROM ext_partnertotals AS cur
See it on sqlfiddle.

MySQL two different groupings required in one query

Struggling to do this with one query:
scores
==========
| child_name | week | behaviour_score | test | test_score |
+---------------------------------------------------------+
| jo | 1 | 75 | 1 | 55 |
| jo | 1 | 75 | 2 | 54 |
| jo | 2 | 71 | 1 | 65 |
| jo | 3 | 68 | 1 | 70 |
| jo | 3 | 68 | 2 | 74 |
| jo | 3 | 68 | 3 | 45 |
Each child takes 1 to n tests each week. Behaviour is recorded as a value for the week, but is stored in each row - so e.g. jo's behaviour for week 1 is 75, and for week 3 is 68. It's not normalised. I know. Wasn't my call.
The table contains records like this for many children.
I am trying to return 1 row per child, with name, sum of behaviour, and sum of test scores.
But because behaviour isnt normalised it must only count the value once per week.
So sum of behaviour above is 75+71+68
And sum of test scores is 55+54+65+70+74+45
My first attempt was
SELECT
child_name,
SUM(behaviour_score),
SUM(test_Score)
FROM results
GROUP BY child_name
But of course, that gives too large a value for behaviour score as it doesnt account for the values being duplicated for a given week.
Is it possible to achieve this with one query?
You need to first reduce the data into one row per child, per week with the total test score but only one (let's take the MAX) behavior score), then base your query on that:
SELECT
child_name,
SUM(behaviour_score),
SUM(test_Score)
FROM (
SELECT child_name, MAX(behavior_score), SUM(test_Score)
FROM result GROUP BY child_name, week
) AS OnePerWeek
GROUP BY child_name