MDX Help: - Comparing Values in Two Max Time Periods within a larger Set of Time Periods to Populate an Indicator - sql-server-2008

I'm brand new to MDX and need some help. In SSRS I have a dataset that pulls from an SSAS cube. The dataset always contains six months of data. What I need to be able to do is to compare a value for the max(timeID) with a value for the second max(timeID) and if the value for the max(timeID) > value for the second max(timeID) than the arrow goes up in the indicator, etc...
So for the dataset below I would subtract 20130201's Value which is 8 from
20130301's Value which is 10. The result would be a positive number and the indicator would be an upward pointing green arrow. If it was 0 it would be straight and if negative the arrow would be red and point down. I understand how to deal with the indicator - that's not an issue. It's the MDX I need help with.
20130201 8
20130301 10
20121201 4
I can write it in SQL and it would look like this.
Select Item, case when sum(Time1ContentCount) > sum(Time2ContentCount) then 3 when sum(Time1ContentCount) = sum(Time2ContentCount) then 2 when sum(Time1ContentCount) sum(Time2ContentCount) then 1 end as Indicator, sum(Time1ContentCount) as Time1Count, sum(Time2ContentCount) as Time2Count from (Select timeID, dc.Item, Case when timeID = (Select max(timeID) from FactUsage) then count(fu.Contentid) else 0 END as Time1ContentCount, Case when timeID = (Select max(timeID) from FactUsage where timeID <>(Select max(timeID) from FactUsage)) then count(fu.Contentid) else 0 END as Time2ContentCount from factUsage fu INNER JOIN dimContent dC on dc.ContentID = fu.ContentID WHERE TimeID in (Select distinct top 6 timeid from factUsage order by timeID desc) Group by timeID, Item) a group by Item
Thanks so much for your help!
Edit:
I changed the statement to read as follows for the indicator.
WITH Member MEASURES.Indicator AS (
IIF(( [Measures].[Activity], [Time].[Time ID].LastChild ) >
( [Measures].[Activity], [Time].[Time ID].LastChild.PrevMember),3,
(IIF(([Measures].[Activity], [Time].[Time ID].LastChild ) =
([Measures].[Activity], [Time].[Time ID].LastChild.PrevMember), 2,1))))
SELECT {Measures.Indicator} on 0
FROM [DW]
It works when I run it as a query against the cube in SSMS but I tried to put it in the indicator and that doesn't work. Just adding the IIF statement doesn't work either. When I tried to add it into the query or the cube itself so I could just pull from there it errors out with an out of memory error.

I don't know how much you can edit in the MDX expression - or in your report builder, but to get the difference between two values in a series, you can create a measure (in your report) that is the difference between the CurrentMember and PrevMember. Since the time series (timeid) is sorted by the key, it will always be in the right order (or your schema and architecture needs a rework)
So basically, you can do :
WITH
MEMBER MEASURES.GrowthTime AS (
( [Measures].[Value], [TimeID].CurrentMember ) -
( [Measures].[Value], [TimeID].PrevMember )
)
MEMBER MEASURES.GrowthRatio AS (
( [Measures].[Value], [TimeID].CurrentMember ) /
( [Measures].[Value], [TimeID].PrevMember )
)
SELECT { Measures.Value, Measures.GrowthTime, Measures.GrowthRatio } on 0,
[TimeID].CHILDREN on 1
FROM Cube
This is pseudo as i don't know your cube structure. For TimeID you would want it like [DimensionName].[AttributeName].CurrentMember and PrevMember

Related

SQL Inner Join w/ sub query to return difference w/criteria

What am I doing:
I'm attempting to take two tables, one with 2016 data and one with 2015 data, and subtract the cells in each column to display only the differences greater than or equal to 10,000, rounded to the nearest 100th place, in a new table.
The Issue:
I am able to get the new table to pop up with the correct amounts displayed for the subtraction part only. I'm not able to add any additional criteria to filter the results to display the >= 10000 or the rounding to the 100th spot.
After research it looks like my JOIN needs a subquery to display what i would like, but I've been messing around with it for hours now and I can't seem to get it to display anything when I add a sub. Any assistance would be great. Here is what I have that works without the >= 10000 and rounding:
SELECT
`prioryeardata`.location,
`currentdata`.`2010` - `prioryeardata`.`2010` AS '2010_Difference',
`currentdata`.`2011` - `prioryeardata`.`2011` AS '2011_Difference',
`currentdata`.`2012` - `prioryeardata`.`2012` AS '2012_Difference',
`currentdata`.`2013` - `prioryeardata`.`2013` AS '2013_Difference',
`currentdata`.`2014` - `prioryeardata`.`2014` AS '2014_Difference',
`currentdata`.`2015` - `prioryeardata`.`2015` AS '2015_Difference'
FROM `prioryeardata`
JOIN `currentdata`
ON `prioryeardata`.location = `currentdata`.location;
Have a look at the below query it may help (using sql-server)
select location,Round([2010_Difference],3).[2010_Difference],Round([2011_Difference],3)[2011_Difference]
,Round([2012_Difference],3)[2012_Difference],Round([2013_Difference],3)[2013_Difference]
,Round([2014_Difference],3)[2014_Difference],Round([2015_Difference],3)[2015_Difference] from
( SELECT
prioryeardata.location,
currentdata.year2010 - prioryeardata.year2010 AS [2010_Difference],
currentdata.year2011 - prioryeardata.year2011 AS [2011_Difference],
currentdata.year2012 - prioryeardata.year2012 AS [2012_Difference],
currentdata.year2013 - prioryeardata.year2013 AS [2013_Difference],
currentdata.year2014 - prioryeardata.year2014 AS [2014_Difference],
currentdata.year2015 - prioryeardata.year2015 AS [2015_Difference]
FROM prioryeardata
JOIN currentdata
ON prioryeardata.location = currentdata.location
) t where t.[2015_Difference]>=10000 --or .......
Edit
select location,Round([2010_Difference],3).[2010_Difference],Round([2011_Difference],3)[2011_Difference]
,Round([2012_Difference],3)[2012_Difference],Round([2013_Difference],3)[2013_Difference]
,Round([2014_Difference],3)[2014_Difference],Round([2015_Difference],3)[2015_Difference]
from
(select t.location
,case when [2010_Difference]>10000 then [2010_Difference] Else 0 End as [2010_Difference]
,case when [2011_Difference]>10000 then [2011_Difference] Else 0 End as [2011_Difference]
,case when [2012_Difference]>10000 then [2012_Difference] Else 0 End as [2012_Difference]
,case when [2013_Difference]>10000 then [2013_Difference] Else 0 End as [2013_Difference]
,case when [2014_Difference]>10000 then [2014_Difference] Else 0 End as [2014_Difference]
,case when [2015_Difference]>10000 then [2015_Difference] Else 0 End as [2015_Difference]
from
( SELECT
prioryeardata.location,
currentdata.year2010 - prioryeardata.year2010 AS [2010_Difference],
currentdata.year2011 - prioryeardata.year2011 AS [2011_Difference],
currentdata.year2012 - prioryeardata.year2012 AS [2012_Difference],
currentdata.year2013 - prioryeardata.year2013 AS [2013_Difference],
currentdata.year2014 - prioryeardata.year2014 AS [2014_Difference],
currentdata.year2015 - prioryeardata.year2015 AS [2015_Difference]
FROM prioryeardata
JOIN currentdata
ON prioryeardata.location = currentdata.location
) t where t.[2010_Difference]>=10000 or t.[2011_Difference]>=10000 or t.[2012_Difference]>=10000
or t.[2013_Difference]>=10000 or t.[2014_Difference]>=10000 or t.[2015_Difference]>=10000
)tt
If you want cells to show blank instead of a value, use a pattern like this under your SELECT:
CASE WHEN `currentdata`.`2015` - `prioryeardata`.`2015` >= 10000 THEN
`currentdata`.`2015` - `prioryeardata`.`2015` ELSE NULL END AS '2015_Difference'
strictly speaking the else null is unnecessary, I just put it in for your learning benefit
If you want to only show rows where the difference is greater than ten k put this in on the end of your query:
WHERE
`currentdata`.`2015` - `prioryeardata`.`2015` >= 10000
If you want to only show rows where all years were over ten k, add similar filters for other years separated by AND. If you want to show rows where any year was over ten k, separate them with OR
To round values to the nearest 100 (i.e. 12345 becomes 12300) I believe you would use
ROUND(12345,-2)

how to know the source table from a complex sql query

PFB the query in which I want know the actual table where I can find these (pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK )....
select count(1),pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK from
(SELECT vw1.pin_ein, vw1.engineer_pin,
vw1.transaction_date, vw1.effective_week,
vw1.stores_tools_cost,
(vw1.stores_total_cost - vw1.stores_tools_cost
) stores_total_cost_excl_tools,
vw1.item_count, vw1.stores_visit_count,
CASE
WHEN vw1.stores_total_cost <
5
THEN vw1.stores_visit_count
END stores_low_cost_visit_count,
vw1.actual_ouc ouc, er.eng_name engineer_name,
CASE
WHEN c.home_parked IS NOT NULL
THEN c.home_parked
ELSE 'N'
END home_parker,
CASE
WHEN c.home_parked IS NOT NULL
THEN c.commute_time
ELSE -99
END commute_time,
vw1.stores_com_cost ---v9.3---
FROM (SELECT pin_ein, engineer_pin, actual_ouc,
transaction_date, effective_week,
NVL
(SUM
(CASE
WHEN ( cow LIKE '%TOOL%'
OR cow LIKE
'%TOOLE%'
)
THEN transaction_value
END
),
0
) stores_tools_cost,
SUM
(transaction_value
) stores_total_cost,
SUM (transaction_quantity)
item_count,
COUNT
(DISTINCT sta_code
) stores_visit_count,
NVL
(SUM
(CASE
WHEN cow in (SELECT cow FROM orbit_odw.stores_cow_ref)
THEN transaction_value
END
),
0
) stores_com_cost ---v9.3---
FROM orbit_odw.stores_transaction_dtls
WHERE effective_week BETWEEN 201543
AND 201610
/***Ver 6.0---last 13 weeks data to be considered***/
AND transaction_date
BETWEEN to_date('19-10-2015','dd-mm-yyyy')
AND to_date('06-03-2016','dd-mm-yyyy')
/***Ver 6.0---last 13 weeks data to be considered***/
GROUP BY pin_ein,
engineer_pin,
actual_ouc,
transaction_date,
effective_week) vw1,
(SELECT *
FROM orbit_odw.dim_wms_rmdm
WHERE current_status = 1) er,
(SELECT engineer_ein, commute_time,
home_parked
FROM orbit_odw.eng_parking_at_home_dtls
WHERE rec_end_date > SYSDATE
AND home_parked = 'Y') c
WHERE TO_CHAR (vw1.pin_ein) = er.ein
AND vw1.pin_ein = c.engineer_ein(+)) group by pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK having count(1)>1;
Please help..
thanks in advance
Basically if i understand your problem correctly. You need to understand from where your outer SELECT is fetching data. So there is a simple rule set used to get these data. Steps are as follows.
Check the column output i.e in your case it's
pin_ein,engineer_pin,transaction_date,EFFECTIVE_WEEK
Check the inline view or table from which your outer query is
fetching the data. In your case its the only inline view you have
used --> So bit easy to identify :P
Now to identify how your inline view VW1 is populating data. In your
case table orbit_odw.stores_transaction_dtls is used to populate the
required fields.
Hope this much information is required. Also for simple queries you can always go to ALL_TAB_COLUMNS system tables to identify a table's column easily.

WHERE clause in SSRS expression for max function

I have for example a query with return something as it
route value
1 3
2 2
3 4
4 5
5 1
then I need to put in 2 textbox the max and the min route so in sql this would be
select top 1 route from table where value=(select max(value) from table)
I add a image done in excel, how this would be.
I believe this is so easy but I dont have idea how to get it.
I got using expression, this was extactly expression
="Route "+
Convert.ToString (
Lookup(max(fields!value.Value),fields!value.Value ,fields!route.Value,"mydataset")
)
changing max for min, for the other...
thanks everyone.
I believe the query you're looking for would be:
With Min_Max_CTE as (
Select MIN(value) as Min_Value
, MAX(value) as Max_Value
From Table
)
Select Top 1 'Min' as Type
, T.route
, T.value
From Table T
Inner Join Min_Max_CTE CTE
on T.value = CTE.Min_Value
Union All
Select Top 1 'Max' as Type
, T.route
, T.value
From Table T
Inner Join Min_Max_CTE CTE
on T.value = CTE.Max_Value
Order by Type desc --This will put the Min Route first followed by the Max Route
Then, put that query into a dataset, and then create a tablix and use the Type, route, and value fields to return the minimum route and the maximum route. It should end up being set up just like your excel section with the min and max routes above.
You can do this SSRS by using a couple of separate tables. Your example data:
And two tables in the Designer:
Since the tables only have header rows, only the first row in the table will be displayed.
To make sure we get the MAX and MIN values in the two tables, each table needs to order its Dataset appropriately, i.e. by Value by descending and ascending respectively.
MAX table:
MIN table:
Which gives your expected result:

Replace mysql user defined variable

I have a query which works great given that the result is only one number, but now I need to allow for multiple rows to be returned and the query cannot handle that because it uses a user define variable... here is original procedure
CREATE DEFINER=`root`#`%` PROCEDURE `MapRank`(pTankID bigint,pMapID int, pColor int(2))
BEGIN
SET #RankNumber:=0;
select RankNumber
from
(select
TankID,
#RankNumber:=#RankNumber+1 as RankNumber,
MapID,
Color
from MAPDATA WHERE MapID = pMapID order by Rank DESC, TotalPP DESC) Query1 where TankID = pTankID AND COLOR = pColor ;
END
this returns a single number, essentially counting the number of records down it is, giving me the "row" location.
now I need to change it to give me all rows with out the where for mapid and color, so that I can see all ranks for all mapid/color combo
this is what I have that currently does not work
SET #RankNumber:=0;
select
RankNumber,MapID,COlor
from
(select
TankID,
#RankNumber:=#RankNumber + 1 as RankNumber,
MapID,
Color
from
MAPDATA
order by TotalPP DESC) Query1
where
TankID = 18209 ORDER BY RankNumber
the yielding query result looks as such:
1062 3 1
3544 3 0
6717 17 1
6752 17 3
7453 3 2
7860 17 0
7984 17 2
9220 3 3
if I run manually lets say, map id 3 and color 3 which says rank number is 9220 with the FIRST query I get this
6022
I need this to be able to be done possibly from multiple MySQL connections so ideally done without use of a temporary variable since its possible another person may come in and use that... any help would be great.
After digging and messing more I have found the solution to be to set the variable back to zero from within the outer select.. and since user defined variable are connection level and I utilize pooling we should never have an issue.
SET #RankNumber:=0;
select
RankNumber,MapID,COlor, #RankNumber:=0
from
(select
TankID,
#RankNumber:=#RankNumber + 1 as RankNumber,
MapID,
Color
from
MAPDATA
order by MapID, Rank DESC, TotalPP DESC ) Query1
where
TankID = pTankID ORDER BY RankNumber;

Select data which have same letters

I'm having trouble with this SQL:
$sql = mysql_query("SELECT $menucompare ,
(COUNT($menucompare ) * 100 / (SELECT COUNT( $menucompare )
FROM data WHERE $ww = $button )) AS percentday FROM data WHERE $ww >0 ");
$menucompare is table fields names what ever field is selected and contains data bellow
$button is the week number selected (lets say week '6')
$ww table field name with row who have the number of week '6'
For example, I have data in $menucompare like that:
123456bool
521478bool
122555heel
147788itoo
and I want to select those, who have same word in the last of the data and make percentage.
The output should be like that:
bool -- 50% (2 entries)
heel -- 25% (1 entry)
itoo -- 25% (1 entry)
Any clearness to my SQL will be very appreciated.
I didn't find anything like that around.
Well, keeping data in such format probably not the best way, if possible, split the field into 2 separate ones.
First, you need to extract the string part from the end of the field.
if the length of the string / numeric parts is fixed, then it's quite easy;
if not, you should use regular expressions which, unfortunately, are not there by default with MySQL. There's a solution, check this question: How to do a regular expression replace in MySQL?
I'll assume, that numeric part is fixed:
SELECT s.str, CAST(count(s.str) AS decimal) / t.cnt * 100 AS pct
FROM (SELECT substr(entry, 7) AS str FROM data) AS s
JOIN (SELECT count(*) AS cnt FROM data) AS t ON 1=1
GROUP BY s.str, t.cnt;
If you'll have regexp_replace function, then substr(entry, 7) should be replaced to regexp_replace(entry, '^[0-9]*', '') to achieve the required result.
Variant with substr can be tested here.
When sorting out problems like this, I would do it in two steps:
Sort out the SQL independently of the presentation language (PHP?).
Sort out the parameterization of the query and the presentation of the results after you know you've got the correct query.
Since this question is tagged 'SQL', I'm only going to address the first question.
The first step is to unclutter the query:
SELECT menucompare,
(COUNT(menucompare) * 100 / (SELECT COUNT(menucompare) FROM data WHERE ww = 6))
AS percentday
FROM data
WHERE ww > 0;
This removes the $ signs from most of the variable bits, and substitutes 6 for the button value. That makes it a bit easier to understand.
Your desired output seems to need the last four characters of the string held in menucompare for grouping and counting purposes.
The data to be aggregated would be selected by:
SELECT SUBSTR(MenuCompare, -4) AS Last4
FROM Data
WHERE ww = 6
The divisor in the percentage is the count of such rows, but the sub-stringing isn't necessary to count them, so we can write:
SELECT COUNT(*) FROM Data WHERE ww = 6
This is exactly what you have anyway.
The divdend in the percentage will be the group count of each substring.
SELECT Last4, COUNT(Last4) * 100.0 / (SELECT COUNT(*) FROM Data WHERE ww = 6)
FROM (SELECT SUBSTR(MenuCompare, -4) AS Last4
FROM Data
WHERE ww = 6
) AS Week6
GROUP BY Last4
ORDER BY Last4;
When you've demonstrated that this works, you can re-parameterize the query and deal with the presentation of the results.