MDX combine two measures with different timelines on one timeline - date

I have two measures Time_Quantity and Time2_Quality. These measures refer to two different timelines, Time and Time2. But as an output I want to have a query which shows me the two measures on one single timeline. I guess I have to combine the time and time2 timeline, but how? This is what i have so far:
WITH
MEMBER [Time_Quantity] AS
(
[Measures].[Quantity]
,[Measures].[Time-Quantity]
,[Time Dates].[Time Year-Quarter-Month-Date]
)
MEMBER [Time2_Quality] AS
(
[Measures].[Quality]
,[Measures].[Time2-Quantity]
,[Time2 Dates].[Time2 Year-Quarter-Month-Date]
)
SELECT
{
Time_Quantity
,Time2_Quality
} ON COLUMNS
,Timeline ON ROWS // **<<how to combine Time and Time2 Timeline in one single Timeline?**
FROM [Cube];

I think that you are looking for something like below. It might need extra development because it took 13sec.
WITH MEMBER [Measures].[link_sales] AS
(LinkMember([Date].[Calendar].CURRENTMEMBER, [Ship Date].[Calendar]),[Measures].[Internet Sales Amount])
MEMBER [Measures].[link_tax] AS
(LinkMember([Date].[Calendar].CURRENTMEMBER, [Ship Date].[Calendar]),[Measures].[Internet Tax Amount])
SELECT
{[Measures].[link_sales],[Measures].[link_tax]} ON COLUMNS,
NON EMPTY [Date].[Calendar].MEMBERS ON ROWS
FROM [Adventure Works]
Result (time: 13sec)
link_sales link_tax
All Periods 29358677.2207 2348694.2301
CY 2005 3105587.3292 248446.991
H2 CY 2005 3105587.3292 248446.991
Q3 CY 2005 1349136.7362 107930.9407
July 2005 349490.1938 27959.2159

Related

Optimize KDB query time to get rolling average price from each contributor

Each time a contributor gives an updated price I want to use this quote along with the latest prices of other quotes to calculate the total average at that moment.
t:`time xasc flip (`userID`time`price)!(`quote1`quote2`quote3`quote3`quote3`quote3`quote4`quote2`quote4`quote3`quote2`quote3`quote1`quote3`quote4`quote1`quote4`quote2`quote2`quote4;(21:11:37 03:13:29 15:35:39 09:59:13 04:34:15 13:09:01 21:21:55 16:54:39 04:03:04 18:22:39 17:05:44 05:08:40 07:35:50 15:46:15 17:32:29 19:42:47 03:28:48 04:20:03 14:16:55 09:02:12);86.4 84.4 54.26 7.76 63.75 97.61 53.97 71.63 38.86 52.23 87.25 65.69 96.25 37.15 17.45 58.97 95.51 61.59 70.25 35.5)
Desired output below
delete userIDPriceList,userIDComps from t,'raze {[idx;tab] select avgPrice:avg price, userIDPriceList:price,userIDComps:userID from select last price by userID from t where i <= idx}[;t] each til count t
userIDPriceList,userIDComps columns are not required in final output
Performance is slow and looking for better way to calculate.
q) \t do[200000;delete userIDPriceList,userIdComps from t,'raze {[idx;tab] select avgPrice:avg price, userIDPriceList:price,userIDComps:userID from select last price by userID from t where i <= idx}[;t] each til count t]
10152j
Thanks in advance
Based on your clarified requirements, another approach is to accumulate using scan:
update avgPrice:avg each{x,(1#y)!1#z}\[();userID;price] from t
Igors solution is faster if the data is static (aka you can prep the table with the attribute once).
Below code gives average of all previous prices for given userID including current row:
ungroup 0!select time, price, avgPrice: avgs price by userID from t
Just ensure that t is appropriately sorted by time before getting averages.
According to your comment to one of the answers, you're "trying to take the average prices of each userID as of the time of the record while ignoring any future records."
This query will do exactly that:
select userID,time,price,avgPrice:(avgs;price)fby userID from t
A query of yours (delete userIDPriceList ...) results in something different as #Anton Dovzhenko pointed out in his comment to your original question.
Update
After reading your comment I think I understood your requirement. Probably you could do this.
prices:exec `s#time!price by userID from t;
update avgPrice:avg each flip prices[;time] from t

how to get min or max date on columns in mdx query

what mdx query logic could i implement for this example to get two rows in result set for hrid = 1 with 1/1/16 as min date(start) for first row where someattribut shows up on column with value 'A'
and 1/15/16 as min date(start) for second row where someattribute has value of 'B' and measure.whatevers has its aggregation for whatever data corresponds to that dimension row.
Im trying to just look at january 2016
everything ive tried i seem to get min date values of 1/1/1900 or both rows have value of 1/1/2016 or i get errors since i cant figure it out.
heres my mdx sample:
WITH MEMBER [Measures].[Start] as
(
-- min date that the combination of someattribute and hrid have certain
-- value withing the range of the where clause restriction of january 2016
SELECT {
[Measures].[Start]
, [Measures].[Whatevers]
} ON COLUMNS
, NON EMPTY {
[Agent].[HRID].children
* [Agent].[someAtribute].Members
} ON ROWS
FROM [RADM_REPORTING]
WHERE (
[Date].[Date View].[Month].&[201601]
)
this works, but it feels kind of like a hack or maybe it feels like its not robust, I am not familiar enough with mdx to be able to make that call.
WITH MEMBER [Measures].[Start] as
filter([Date].[Date View].[Month].&[201601].children,
[Measures].[Whatevers]).item(0).membervalue
Here is a potential direction that is more general:
WITH
MEMBER [Measures].[Start] AS
Min
(
(EXISTING
[Date].[Date].[Date].MEMBERS)
,IIF
(
[Measures].[Internet Sales Amount] = 0
,NULL
,[Date].[Date].CurrentMember.MemberValue
)
)
SELECT
NON EMPTY
{
[Measures].[Start]
,[Measures].[Internet Sales Amount]
} ON COLUMNS
,NON EMPTY
[Product].[Product Categories].[Product] ON ROWS
FROM [Adventure Works]
WHERE
[Date].[Calendar].[Calendar Year].&[2005];
It gives the following:

Tableau - Calculating average where date is less than value from another data source

I am trying to calculate the average of a column in Tableau, except the problem is I am trying to use a single date value (based on filter) from another data source to only calculate the average where the exam date is <= the filtered date value from the other source.
Note: Parameters will not work for me here, since new date values are being added constantly to the set.
I have tried many different approaches, but the simplest was trying to use a calculated field that pulls in the filtered exam date from the other data source.
It successfully can pull the filtered date, but the formula does not work as expected. 2 versions of the calculation are below:
IF DATE(ATTR([Exam Date])) <= DATE(ATTR([Averages (Tableau Test Scores)].[Updated])) THEN AVG([Raw Score]) END
IF DATEDIFF('day', DATE(ATTR([Exam Date])), DATE(ATTR([Averages (Tableau Test Scores)].[Updated]))) > 1 THEN AVG([Raw Score]) END
Basically, I am looking for the equivalent of this in SQL Server:
SELECT AVG([Raw Score]) WHERE ExamDate <= (Filtered Exam Date)
Below a workbook that shows an example of what I am trying to accomplish. Currently it returns all blanks, likely due to the many-to-one comparison I am trying to use in my calculation.
Any feedback is greatly appreciated!
Tableau Test Exam Workbook
I was able to solve this by using Custom SQL to join the tables together and calculate the average based on my conditions, to get the column results I wanted.
Would still be great to have this ability directly in Tableau, but whatever gets the job done.
Edit:
SELECT
[AcademicYear]
,[Discipline]
--Get the number of student takers
,COUNT([Id]) AS [Students (N)]
--Get the average of the Raw Score
,CAST(AVG(RawScore) AS DECIMAL(10,2)) AS [School Mean]
--Get the number of failures based on an "adjusted score" column
,COUNT([AdjustedScore] < 70 THEN 1 END) AS [School Failures]
--This is the column used as the cutoff point for including scores
,[Average_Update].[Updated]
FROM [dbo].[Average] [Average]
FULL OUTER JOIN [dbo].[Average_Update] [Average_Update] ON ([Average_Update].[Id] = [Average].UpdateDateId)
--The meat of joining data for accurate calculations
FULL OUTER JOIN (
SELECT DISTINCT S.[Id], S.[LastName], S.[FirstName], S.[ExamDate], S.[RawScoreStandard], S.[RawScorePercent], S.[AdjustedScore], S.[Subject], P.[Id] AS PeriodId
FROM [StudentScore] S
FULL OUTER JOIN
(
--Get only the 1st attempt
SELECT DISTINCT [NBOMEId], S2.[Subject], MIN([ExamDate]) AS ExamDate
FROM [StudentScore] S2
GROUP BY [NBOMEId],S2.[Subject]
) B
ON S.[NBOMEId] = B.[NBOMEId] AND S.[Subject] = B.[Subject] AND S.[ExamDate] = B.[ExamDate]
--Group in "Exam Periods" based on the list of periods w/ start & end dates in another table.
FULL OUTER JOIN [ExamPeriod] P
ON S.[ExamDate] = P.PeriodStart AND S.[ExamDate] <= P.PeriodEnd
WHERE S.[Subject] = B.[Subject]
GROUP BY P.[Id], S.[Subject], S.[ExamDate], S.[RawScoreStandard], S.[RawScorePercent], S.[AdjustedScore], S.[NBOMEId], S.[NBOMELastName], S.[NBOMEFirstName], S.[SecondYrTake]) [StudentScore]
ON
([StudentScore].PeriodId = [Average_Update].ExamPeriodId
AND [StudentScore].Subject = [Average].Subject
AND [StudentScore].[ExamDate] <= [Average_Update].[Updated])
--End meat
--Joins to pull in relevant data for normalized tables
FULL OUTER JOIN [dbo].[Student] [Student] ON ([StudentScore].[NBOMEId] = [Student].[NBOMEId])
INNER JOIN [dbo].[ExamPeriod] [ExamPeriod] ON ([Average_Update].ExamPeriodId = [ExamPeriod].[Id])
INNER JOIN [dbo].[AcademicYear] [AcademicYear] ON ([ExamPeriod].[AcademicYearId] = [AcademicYear].[Id])
--This will pull only the latest update entry for every academic year.
WHERE [Updated] IN (
SELECT DISTINCT MAX([Updated]) AS MaxDate
FROM [Average_Update]
GROUP BY[ExamPeriodId])
GROUP BY [AcademicYear].[AcademicYearText], [Average].[Subject], [Average_Update].[Updated],
ORDER BY [AcademicYear].[AcademicYearText], [Average_Update].[Updated], [Average].[Subject]
I couldn't download your file to test with your data, but try reversing the order of taking the average ie
average(IF DATE(ATTR([Exam Date])) <= DATE(ATTR([Averages (Tableau Test Scores)].[Updated]) then [Raw Score]) END)
as written, I believe you'll be averaging the data before returning it from the if statement, whereas you want to return the data, then average it.

MDX Query with Date Range Filter

I am new to the MDX queries. I am writing a MDX query to select a Measure value across months and I am putting date Range as filter here just to restrict no of Months returned. For eg I want Sales Revenue for each month in Date Range of 01-Jan-2014 to 30-Jun-2014. Ideally, it should give me sales value for six months i.e Jan, Feb, Mar, Apr, May and June. However when i write below query, I get error. PFB the below enter code here`ow query.
Select NON EMPTY {[Measures].[Target Plan Value]} ON COLUMNS,
NON EMPTY {[Realization Date].[Hierarchy].[Month Year].Members} ON ROWS
From [Cube_BCG_OLAP]
( { [Realization Date].[Hierarchy].[Date].&[20140101] :
[Realization Date].[Hierarchy].[Date].&[20141231] })
The error I get is The Hierarchy hierarchy already appears in the Axis1 axis. Here Date and Month Year belong to same dimension table named as Realization Date. Please help me. Thanks in advance.
You were missing the WHERE clause but I guess that was a typo. As your error message tells, you can't have members of the same hierarchy on two or more axes. In situations like this, you can use something like below which in MDX terminology is called Subselect.
Select NON EMPTY {[Measures].[Target Plan Value]} ON COLUMNS,
NON EMPTY {[Realization Date].[Hierarchy].[Month Year].Members} ON ROWS
From (
SELECT
[Realization Date].[Hierarchy].[Date].&[20140101] :
[Realization Date].[Hierarchy].[Date].&[20141231] ON COLUMNS
FROM [Cube_BCG_OLAP]
)
I like the exists function in this situation:
SELECT
NON EMPTY {[Measures].[Target Plan Value]}
ON COLUMNS,
NON EMPTY
EXISTS(
[Realization Date].[Hierarchy].[Month Year].Members
, {
[Realization Date].[Hierarchy].[Date].&[20140101] :
[Realization Date].[Hierarchy].[Date].&[20141231]
}
)
ON ROWS
FROM [Cube_BCG_OLAP]
Select
[Measures].[Target Plan Value]} On Columns
{
[Realization Date].[Hierarchy].[Date].&[20140101].Parent :
[Realization Date].[Hierarchy].[Date].&[20140631].Parent
}
On Rows
From [Cube_BCG_OLAP]
You need to create this same dimension only for filter in the cube, for example, dimension_filter -> hierarchy_filter -> level_filter

Adding Columns heading to report if no data in a given period

I have a dataset for each record it has a CompanyID, RevenueMonth, RevenueYear, Revenue
When I create the report, I am grouping each CompanyID and showing their monthly revenue for a given year.
But in a given year, not all companies have any revenues for a particular month.
Example:
A sample record would look like:
CompanyID, RevenueMonth, RevenueYear, Revenue
1,05,2013,5.00
1,08,2013,6.00
1,03,2013,3.00
End Result, I would like my report to look like this with CompanyID 1.
Company ID|01|02|03|04|05|06|07|08|09|10|11|12
1 0.00|0.00|3.00|0.00|5.00|0.00|0.00|6.00|0.00|0.00|0.00|0.00
In my current Report, it will only fill column headings with March (03), May (05) and August (08).
Company ID|03|05|08
1 3.00|5.00|6.00
How do I get my Report to add the missing months for the year?
I hope my questions is clear.
Database level
Since you're only returning a year at a time, you can create a calendar table and add this to your result set:
Keeping it as simple as possible, with the date table coming from a CTE:
with months as -- get required year/months
(
select RevenueYear = 2013
, RevenueMonth = 1
union all
select RevenueYear = 2013
, RevenueMonth = RevenueMonth + 1
from months
where RevenueMonth < 12
)
select CompanyID = coalesce(r.CompanyID, c.companyID)
, RevenueMonth = coalesce(r.RevenueMonth, m.RevenueMonth)
, RevenueYear = coalesce(r.RevenueYear, m.RevenueYear)
, Revenue = isnull(r.Revenue, 0.0)
from months m
cross join (select distinct CompanyID from records) c -- make sure all companies included
left join records r on m.RevenueYear = r.RevenueYear
and m.RevenueMonth = r.RevenueMonth
SQL Fiddle with demo.
This will return a year/month for each company in the result set.
In the long run it would be better to move from a CTE to a permanent calendar table in the database.
You can then implement this in the report using a matrix style tablix.
Report level
If you'd prefer to do this at the report level, you can set up a table-style tablix with 12 permanent columns, one for each month, then populate the month revenue cells with expressions like:
=Sum(IIf(Fields!RevenueMonth.Value = 2, Fields!Revenue.Value, Nothing)
For the February column.
This would work with your existing dataset without any database code changes.