SSRS Matrix percentages - reporting-services

Here's the report:
This is how I got the percentages for column the '%Change of most recent year".
=((Last(Fields!Quantity.Value,"Child") - First(Fields!Quantity.Value)) / First(Fields!Quantity.Value))`
= ((54675 - 55968)/55968 ) = -2.31%'
= ((54675 - 57849)/57849) = -5.49%'
It will always take the first year '2012' in this case and get the percentages against each other year. If I enter the years 2005,2004,2003,2002,2001 it will always take the first year and do a percentages against each additional year. 2005 to 2004, 2005 to 2003, 2005 to 2002 and so on. I can have as many as 2 column (year) to many columns.
I need to do it for the Total and Subtotal but it won't work because it's in a different scope.
data is = row Child group
Sub Total: = row Parent group
Total: = row Total group
Year = Column Period group
Query use to get result.
SELECT MEMBERSHIP_CODE
, PERIOD, COUNT(DISTINCT ID) AS Distinct_ID
, SUM(QUANTITY) AS Quantity
, '01-Personal' AS Child
, '01-Overall' AS Parent
, 'Total' as Total
FROM vf_Sshot AS vfs
INNER JOIN vProd AS vP ON vfs.PRODUCT_CODE = vP.PRODUCT_CODE
INNER JOIN vMem_Type vMT on vMT.Member_Type = vfs.Member_Type
WHERE (PERIOD IN ( (SELECT Val from dbo.fn_String_To_Table(#Periods,',',1))))
AND (vMT.MEMBER_TYPE NOT IN ('a','b','c'))
AND (vfs.STATUS IN ( 'A', 'D', 'C'))
AND (MEMBERSHIP_CODE NOT IN ('ABC', 'DEF' ))
and vP.PROD_TYPE in ('DUE','MC','SC')
and vMT.Member_Record = '1'
GROUP BY MEMBERSHIP_CODE, PERIOD
Any ideas?
How would I produce this output?
TOTAL: 57,573 58,941 57,573 61,188 57,573 61,175 57,175

This is the easiest way of solving your problem. In your query, identify the sum for the latest period on a separate column (you can transform your query into a CTE, so that you don't have to change your base query a lot):
WITH query AS (
SELECT MEMBERSHIP_CODE
, PERIOD, COUNT(DISTINCT ID) AS Distinct_ID
, SUM(QUANTITY) AS Quantity
, '01-Personal' AS Child
, '01-Overall' AS Parent
, 'Total' as Total
...
UNION
SELECT
...
)
SELECT
A.MEMBERSHIP_CODE,
A.PERIOD,
A.Distinct_ID,
A.Child,
A.Parent,
A.Total,
A.Quantity,
B.Quantity AS LastPeriodQuantity
FROM
query A INNER JOIN
(SELECT *, ROW_NUMBER() OVER(PARTITION BY MEMBERSHIP_CODE, Distinct_ID, Child, Parent ORDER BY PERIOD DESC) as periodOrder FROM query) B ON
A.MEMBERSHIP_CODE = B.MEMBERSHIP_CODE AND
A.DISTINCT_ID = B.DISTINCT_ID AND
A.Parent = B.Parent AND
A.Child = B.Child AND
A.Total = B.Total AND
B.PeriodOrder = 1
And then on all your totals/subtotals/columns you will be accessing a column that is being grouped/filtered by the same rules than your denominator. Your expression can remain, for all cells, something like this:
=(Fields!LastPeriodQuantity.Value - Fields!Quantity.Value) / Fields!Quantity.Value

Related

Merging two queries to get a single result in MySQL

I have the following two codes, I need to get the percentage by dividing the 'for_2018_19' by the 'total'. I don't know how to merge them and get a single result which is the percentage.
select sum(maternities) as total from merged
where City = 'Jeza' and Group = 'Unknown';
select sum(Maternities) as for_2018_19 from merged
where Year = '2016/17') percentage ;
You use bth query as the only give back single data, as subqueries
But yu should keep in mind that group is a reserved word, and you should avoid it
SELECT
(select sum(maternities) from merged
where City = 'Jeza' and `Group` = 'Unknown')/
(select sum(Maternities) from merged
where Year = '2016/17') as percentage
You can do next:
select
-- divide partial sum by total
sum(if(Year = '2016/17', maternities, 0)) /
sum(if((City = 'Jeza' and `Group` = 'Unknown'), maternities, 0))
from merged;
you can also use:
select sum(Maternities)*100.0/(select sum(maternities) as total from merged
where City = 'Jeza' and Group = 'Unknown') as percent from merged
where Year = '2016/17'
select b.for_2018_19 / a.total
from ( select sum(maternities) as total
from merged
where City = 'Jeza'
and Group = 'Unknown' ) a
, ( select sum(Maternities) as for_2018_19
from merged
where Year = '2016/17'
) b

GROUP_CONCAT split in different columns MYSQL

I am working with a TABLE, need logical help
This query:
SELECT
DATE_FORMAT(tran_date, '%M %Y') AS month_name,
SUM(IF(c.ctype = 4, gl.amount * -1, 0)) AS sales,
GROUP_CONCAT(DISTINCT(d.name)) AS d_name
FROM
gl_trans AS gl, company_chart_masters AS a,
company_chart_types AS t, company_chart_classes AS c, dimensions as d
WHERE
(c.ctype = 4 OR c.ctype = 5) AND
d.id = gl.dimension2_id AND
gl.account = a.account_code AND
a.account_type = t.id AND
t.class_id = c.id AND
DIMENSION2_id = gl.dimension2_id
GROUP BY
month_name
ORDER BY
month_name DESC
Produces this result:
As you can see the output of the query has 3 columns month_name, sale and pos where the pos column is separated with comma. But what I want now is to split the pos in different columns (factor matab, Rawalpindi matab, ...).
My second problem is that I also split the sale column like a split the pos column ans show sale accordingly pos wise and this sale column also shows in different columns after splitting.
Is there any other way to split the RESULT and show each value in the column and same ROW? In the same result?
Expected result:
Month_name Factor_Matab Rawalpindi_Matab
-----------------------------------------------
feb 2020 25000 78236
mar 2020 26366 82367
As I am new at stack overflow so I don't know how to show this expected result in tabular form
For get your expectation you should to use pivot table pattern:
SELECT
month_name,
-- pivot table
SUM(IF(dimension = 'Factor_Matab', sales, 0)) AS Factor_Matab,
SUM(IF(dimension = 'Rawalpindi_Matab', sales, 0)) AS Rawalpindi_Matab
FROM (
-- Select data grouped by month and dimension as tmp
SELECT
DATE_FORMAT(tran_date, '%M %Y') AS month_name,
d.name AS dimension,
SUM(IF(c.ctype = 4, gl.amount * -1, 0)) AS sales
FROM
gl_trans AS gl,
company_chart_masters AS a,
company_chart_types AS t,
company_chart_classes AS c,
dimensions as d
WHERE (c.ctype = 4 OR c.ctype = 5) AND
d.id = gl.dimension2_id AND
gl.account = a.account_code AND
a.account_type = t.id AND
t.class_id = c.id AND
DIMENSION2_id = gl.dimension2_id
GROUP BY month_name, d.name
) tmp
-- group tmp table by month
GROUP BY month_name
ORDER BY month_name DESC;

MySql - Selecting MAX & MIN and returning the corresponding rows

I trying to get the last 6 months of the min and max of prices in my table and display them as a group by months. My query is not returning the corresponding rows values, such as the date time for when the max price was or min..
I want to select the min & max prices and the date time they both occurred and the rest of the data for that row...
(the reason why i have concat for report_term, as i need to print this with the dataset when displaying results. e.g. February 2018 -> ...., January 2018 -> ...)
SELECT metal_price_id, CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term, max(metal_price) as highest_gold_price, metal_price_datetime FROM metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
ORDER BY metal_price_datetime DESC
I have made an example, extract from my DB:
http://sqlfiddle.com/#!9/617bcb2/4/0
My desired result would be to see the min and max prices grouped by month, date of min, date of max.. and all in the last 6 months.
thanks
UPDATE.
The below code works, but it returns back rows from beyond the 180 days specified. I have just checked, and it is because it joining by the price which may be duplicated a number of times during the years.... see: http://sqlfiddle.com/#!9/5f501b/1
You could use twice inner join on the subselect for min and max
select a.metal_price_datetime
, t1.highest_gold_price
, t1.report_term
, t2.lowest_gold_price
,t2.metal_price_datetime
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, max(metal_price) as highest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t1 on t1.highest_gold_price = a.metal_price
inner join (
select a.metal_price_datetime
, t.lowest_gold_price
, t.report_term
from metal_prices_v2 a
inner join (
SELECT CONCAT(MONTHNAME(metal_price_datetime), ' ', YEAR(metal_price_datetime)) AS report_term
, min(metal_price) as lowest_gold_price
from metal_prices_v2
WHERE metal_id = 1
AND DATEDIFF(NOW(), metal_price_datetime) BETWEEN 0 AND 180
GROUP BY report_term
) t on t.lowest_gold_price = a.metal_price
) t2 on t2.report_term = t1.report_term
simplified version of what you should do so you can learn the working process.
You need calculate the min() max() of the periods you need. That is your first brick on this building.
you have tableA, you calculate min() lets call it R1
SELECT group_field, min() as min_value
FROM TableA
GROUP BY group_field
same for max() call it R2
SELECT group_field, max() as max_value
FROM TableA
GROUP BY group_field
Now you need to bring all the data from original fields so you join each result with your original table
We call those T1 and T2:
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R1
ON tableA.group_field = R1.group_field
AND tableA.value = R1.min_value
SELECT tableA.group_field, tableA.value, tableA.date
FROM tableA
JOIN ( ... .. ) as R2
ON tableA.group_field = R2.group_field
AND tableA.value = R2.max_value
Now we join T1 and T2.
SELECT *
FROM ( .... ) as T1
JOIN ( .... ) as T2
ON t1.group_field = t2.group_field
So the idea is if you can do a brick, you do the next one. Then you also can add filters like last 6 months or something else you need.
In this case the group_field is the CONCAT() value

How can I increase the number of years in SQL and in SSRS report?

I have a forecast algorithm
WITH CTE_AllIDs AS
(
SELECT TOP 22 ID = ROW_NUMBER() OVER (ORDER BY (SELECT NULL))
FROM sys.columns
)
SELECT
c.ID
,OrderMonth = CASE WHEN r.ID IS NOT NULL
THEN r.OrderMonth
-- elaborate function to get the short month name and year
ELSE ordermonth + 1
END
,OrderQuantity
,Trend
,Forecast = CASE WHEN Trend IS NOT NULL AND c.ID <> (SELECT MAX(ID) FROM #Temp_Regression)
THEN NULL
-- For the last actual value (September in this example), we want forecast to have the same
-- value as the trendline (instead of NULL). This prevents a gap in the line charts in SSRS.
WHEN Trend IS NOT NULL AND c.ID = (SELECT MAX(ID) FROM #Temp_Regression)
THEN Trend
-- If trend is not found, it means we can calculate a forecast.
-- However, we also need to check if the month for which we calculate the forecast comes after
-- the actual values. Suppose we don't have values for January, then we don't want to calculate
-- a forecast for January as well. Only for the last 3 months of the year in this example.
WHEN Trend IS NULL AND c.ID > (SELECT MAX(ID) FROM #Temp_Regression)
THEN (#slope * (c.ID % 100)) + #intercept
ELSE NULL
END
FROM CTE_AllIDs c
LEFT JOIN #Temp_Regression r ON c.ID = r.ID;
The results
How can I do this in the values of the OrderMoth columns increase by one the? 2023, 2024, etc.
Thanks.
Your Else in your Case Statement will always contain Null. Try this.
ELSE (Select Max(OrderMonth) From #Temp_Regression) + ((C.ID) - (Select Max(ID) From #Temp_Regression))

Calculating payment breakages

I'm currently working on a report to highlight payment breakages, this is based on a customer paying in June, but then failing to pay in July.
I've currently got it set up to do an except query, to check one month and compare it to the next. Similar to below(syntax my not be correct as I have had to edit certain data).
DECLARE #StartDatePaid AS DATETIME
DECLARE #EndDatePaid AS DATETIME
DECLARE #StartDateMissed AS DATETIME
DECLARE #EndDateMissed AS DATETIME
SET #StartDatePaid = '01-Oct-2013'
SET #EndDatePaid = '31-Oct-2013'
SET #StartDateMissed = '01-Nov-2013'
SET #EndDateMissed = '05-Dec-2013'
SELECT d.StoreNo
, d.CustNo
FROM (
--Paid Range
SELECT c.CustNo, m.StoreNo
FROM dbo.tblCont AS c INNER JOIN
dbo.tblContDep AS cd ON c.ContractNo = cd.ContractNo INNER JOIN
dbo.tblCust AS m ON c.CustNo = m.CustNo INNER JOIN
dbo.tblTrans AS mx ON m.CustNo = mx.CustNo AND cd.AgendaCode = mx.AgendaCode INNER JOIN
dbo.tblCalender AS cl ON mx.DateEvent = cl.Date
WHERE (cd.Payment > 0) AND (m.Closed <> 'Y') AND (cd.AgendaCode <> 'OPCLIPMT')
AND mx.DateEvent BETWEEN #StartDatePaid AND #EndDatePaid
GROUP BY c.CustNo, m.StoreNo, mx.DateEvent
EXCEPT
--Missed Range
SELECT c.CustNo, m.StoreNo
FROM dbo.tblCont AS c INNER JOIN
dbo.tblContDep AS cd ON c.ContractNo = cd.ContractNo INNER JOIN
dbo.tblCust AS m ON c.CustNo = m.CustNo INNER JOIN
dbo.tblTrans AS mx ON m.CustNo = mx.CustNo AND cd.AgendaCode = mx.AgendaCode INNER JOIN
dtLookups.dbo.tblCalender AS cl ON mx.DateEvent = cl.Date
WHERE (cd.Payment > 0) AND (m.Closed <> 'Y') AND (cd.AgendaCode <> 'OPCLIPMT') AND (mx.DateEvent BETWEEN #StartDateMissed AND #EndDateMissed )
GROUP BY c.CustNo, m.StoreNo, mx.DateEvent
) AS d
WHERE d.StoreNo IN (72, 114, 121, 139, 185, 241, 266)
GROUP BY
d.StoreNo, d.CustNo
I will be switching it over to be based on calendar months instead of date ranges, my question is how am I best generating several months of breakages at once. To get a month on Month comparison at once, as it is I can only get it to create one months breakages based on supplied data.
Example of desired output
Month| breakges
June | 201
July | 189
Aug | 250
Open to suggestions on best practice also or ways to improve.
I admit I don't understand your query. Assuming your breakage is the first occurrence of missing payment, not the subsequent ones. You can produce the desired output like this:
-- prepare your source data
with cte1 as
(
select
user_id,
date, -- representing month by the first day
missed -- bool flag if payment was missed in that month
from ...
)
-- add a sequence number to the source data ordered by date
with cte2 as
(
select *,
row_number() over(partition by user_id order by date) rn
from cte1
)
-- select those records where payment was missed but the previous was ok
,cte3 as
(
select user_id, date from cte2 a
where a.missed = 1
and exists (
select * from cte2 b
where b.missed = 0
and b.uid = a.uid
and b.rn = a.rn -1
)
)
select date, count(*) as breakage from cte3 group by date