I'm not familiar with the MDX language and I got a problem with a Dataset (DataBatchProcessData), this is the MDX query :
SELECT
NON EMPTY
{
[Measures].[Germ1 Delta Temp In Out Inf]
,[Measures].[Germ2 Delta Temp In Out Sup]
,[Measures].[Germ2 Delta Temp In Out Inf]
,[Measures].[Germ1 Delta Temp In Out Sup]
,[Measures].[Germ Nb Sprays]
} ON COLUMNS
,NON EMPTY
{
[65 Batch Process Data].[Batch Number].[Batch Number].ALLMEMBERS*
[01 Plants].[Plant Name].[Plant Name].ALLMEMBERS*
[04 Production Units].[Production Unit].[Production Unit].ALLMEMBERS*
[65 Batch Process Data].[Steeping Start Date].[Steeping Start Date].ALLMEMBERS
}
DIMENSION PROPERTIES
MEMBER_CAPTION
,MEMBER_UNIQUE_NAME
ON ROWS
FROM
(
SELECT
StrToSet
("{[65 Batch Process Data].[Batch Number].&[1320165073],[65 Batch Process Data].[Batch Number].&[1320165074],[65 Batch Process Data].[Batch Number].&[1320165075]}"
,CONSTRAINED
) ON COLUMNS
FROM
(
SELECT
StrToSet
("[04 Production Unit].[Production Unit].&[1]"
,CONSTRAINED
) ON COLUMNS
FROM
(
SELECT
StrToSet
("[01 Plants].[Plant Name].&[Rostock]"
,CONSTRAINED
) ON COLUMNS
FROM [Supervision]
)
)
)
CELL PROPERTIES
VALUE
,BACK_COLOR
,FORE_COLOR
,FORMATTED_VALUE
,FORMAT_STRING
,FONT_NAME
,FONT_SIZE
,FONT_FLAGS;
This MDX Query was autogenerated by SSRS, but is not working, I got this error when running my report:
Query (8, 9) The restrictions imposed by the CONSTRAINED flag in the STRTOSET function were violated.
I got another DataSet (DataGermination) that is quite similar to this Dataset, and it take the same parameters (not in the same dimension tho) :
SELECT
NON EMPTY
{
[Measures].[Air Temperature Out - Fact Germination Continue]
} ON COLUMNS
,NON EMPTY
{
[81 Germination Continue].[Batch Number].[Batch Number].ALLMEMBERS*
[80 Germination General].[Plant Name].[Plant Name].ALLMEMBERS*
[80 Germination General].[Production Unit].[Production Unit].ALLMEMBERS*
[81 Germination Continue].[Characteristic Date].[Characteristic Date].ALLMEMBERS*
[80 Germination General].[Start Date Unloading].[Start Date Unloading].ALLMEMBERS*
[80 Germination General].[Start Date].[Start Date].ALLMEMBERS*
[80 Germination General].[End Date].[End Date].ALLMEMBERS
}
DIMENSION PROPERTIES
MEMBER_CAPTION
,MEMBER_UNIQUE_NAME
ON ROWS
FROM
(
SELECT
StrToSet
("[80 Germination General].[Production Unit].&[1]"
,CONSTRAINED
) ON COLUMNS
FROM
(
SELECT
StrToSet
("[80 Germination General].[Plant Name].&[Rostock]"
,CONSTRAINED
) ON COLUMNS
FROM
(
SELECT
StrToSet
("{[81 Germination Continue].[Batch Number].&[1320165073],[81 Germination Continue].[Batch Number].&[1320165074],[81 Germination Continue].[Batch Number].&[1320165075]}"
,CONSTRAINED
) ON COLUMNS
FROM [Supervision]
)
)
)
CELL PROPERTIES
VALUE
,BACK_COLOR
,FORE_COLOR
,FORMATTED_VALUE
,FORMAT_STRING
,FONT_NAME
,FONT_SIZE
,FONT_FLAGS;
When I run these query in SSMS, the 2nd one is working (DataGermination), but I don't know why, the dataset DataBatchProcessData is not.
From BOL:
When the CONSTRAINED flag is used, the set specification must contain
qualified or unqualified member names or a set of tuples containing
qualified or unqualified member names enclosed by braces {}. This flag
is used to reduce the risk of injection attacks via the specified
string. If a string is provided that is not directly resolvable to
qualified or unqualified member names, the following error appears:
"The restrictions imposed by the CONSTRAINED flag in the STRTOSET
function were violated.
Looks like you are not using the fully qualified member name for the attributes.
It needs to be
Dimension Name.Hierarchy Name.Level Name.Member Name
or
Dimension Name.Hierarchy Name.Level Name.&[Member Value]
I suspect one of the members you've specified does not exist in the cube.
Easy to test.
If you add the folllowing to a very very simplemdx script does it run?
{[65 Batch Process Data].[Batch Number].&[1320165073]
,[65 Batch Process Data].[Batch Number].&[1320165074]
,[65 Batch Process Data].[Batch Number].&[1320165075]}
Just the following should shed light on whether it recognizes these members:
SELECT
{} ON ROWS
,{
[81 Germination Continue].[Batch Number].&[1320165073]
,[81 Germination Continue].[Batch Number].&[1320165074]
,[81 Germination Continue].[Batch Number].&[1320165075]
} ON COLUMNS
FROM [Supervision];
You were right SouravA, my problem was for the Batch Number.
It is expecting something like [65 Batch Process Data].[Batch Number].&[Batch Number]&[Plant Code]&[Production Unit]
While I was giving him [65 Batch Process Data].[Batch Number].&[Batch Number]
Thank you for your help!
Related
I have a datacube with a dimension of a large number of academic courses. I would like to group the courses (create a set) by the name of the course (using filter and Inst), so that I can calculate some aggregate statistics. i.e. I would ultimately like a list of the number of people doing courses with those groupings (split later by their home geography).
I have four measures, which include
[Measures].[Achievements]
[Measures].[Starts]
[Measures].[Enrolments]
[Measures].[Leavers]
I have managed to make two sets:
CREATE SET [MyDataCube].[BA] AS
{FILTER(
[Aim].[Aim Title].[Aim Title].Members,
(InStr(1, [Aim].[Aim Title].CurrentMember.NAME, "BA ") <> 0)
)
}
GO
CREATE SET [MyDataCube].[BSc] AS
{FILTER(
[Aim].[Aim Title].[Aim Title].Members,
(InStr(1, [Aim].[Aim Title].CurrentMember.NAME, "BSc") <> 0)
)
}
And then I can query a single set:
SELECT
NON EMPTY [AccessCourses] DIMENSION PROPERTIES MEMBER_NAME ON ROWS,
NON EMPTY Hierarchize({DrilldownLevel({[Geography - Learner Home].[Learner Home].[All]})}) DIMENSION PROPERTIES MEMBER_NAME ON COLUMNS
FROM [MyDataCube]
But how can I get a table with [Geography - Learner Home].[Learner Home].[All] on the rows, with a sum of all [Bsc] and [BA] courses on the columns, like:
I would like to do this for [Measures].[Starts].
Something like the following maybe:
WITH
MEMBER [Aim].[Aim Title].[All].[BA] AS
AGGREGATE(
[BA]
)
MEMBER [Aim].[Aim Title].[All].[BSc] AS
AGGREGATE(
[BSc]
)
SELECT
NON EMPTY
[Geography - Learner Home].[Learner Home].MEMBERS ON ROWS,
NON EMPTY
{
[Aim].[Aim Title].[All].[BA]
,[Aim].[Aim Title].[All].[BSc]
} ON COLUMNS
FROM [MyDataCube]
WHERE [Measures].[Starts];
I wanted to do the trend analysis between the dates. For an instance current date- 30 days
30-60 days and so on.Below is the snippet of comparable sql query but same I wanted to do in MDX.
SQL
SELECT
ROUND
(
(
(
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-30) AND DATE(now())
)
-
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-60) AND DATE(now()-30)
)
)
/
(
SELECT
SUM(del_pri_impr)
FROM
reporting.so_sli_calc_val a,
reporting.user_group_tenant b,
reporting.salesorder c
WHERE
created_on BETWEEN DATE(now()-60) AND DATE(now()-30)
) *100
)
,
0
) AS trend
MDX:
WITH
SET [~FILTER] AS
{[Created_Date.Created_Hir].[Created_On].[2014-04-01]:[Created_Date.Created_Hir].[Created_On].[2014-04-30]}
SET [~ROWS] AS
{[Sales Order Attributes SO.Sales_order].[Sales Order ID].Members}
SELECT
NON EMPTY {[Measures].[CONT_AMT_GROSS], [Measures].[CONT_AMT_NET]} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [SALES_ORDER]
WHERE [~FILTER]
As of now I have hard coded the dates, that will come from parameters.
I am facing difficulty in creating the second set and how to do subtraction between two sets in MDX.
You already have the logic on how to obtain sets of date corresponding to "last 30 days from now" and "last 60 to last 30 days from now". So, I am going to skip that part.
NOTE - You would have to use the parameter values while building these sets.
What you want to do here is first find the values corresponding to these sets of dates and then perform operations on them.
You can proceed like this -
WITH
SET [~FILTER] AS
{[Created_Date.Created_Hir].[Created_On].[2014-04-01]:[Created_Date.Created_Hir].[Created_On].[2014-04-30]}
SET [~ROWS] AS
{[Sales Order Attributes SO.Sales_order].[Sales Order ID].Members}
SET [Last30Days] AS
...
SET [Last60ToLast30Days] AS
...
MEMBER [~Last30Days - Now] AS
Aggregate
(
[Last30Days],
[Measures].[SomeMeasure]
)
MEMBER [~Last60Days - Last30Days] AS
Aggregate
(
[Last60ToLast30Days],
[Measures].[SomeMeasure]
)
MEMBER [~Measure] AS
([~Last30Days - Now]-[~Last60Days - Last30Days] )/([~Last60Days - Last30Days] * 100), format_string = '#,##0'
SELECT
NON EMPTY {
[Measures].[CONT_AMT_GROSS],
[Measures].[CONT_AMT_NET],
[~Measure]
} ON COLUMNS,
NON EMPTY [~ROWS] ON ROWS
FROM [SALES_ORDER]
Format_String takes care of rounding.
Not sure if I totally agree with Sourav's answer as I think some form of aggregation will be needed; creating tuples with sets in them may raise an exception.
Here is a simple model, against AdvWrks, that is tested and will do a subtraction for you:
WITH
SET [Set1] AS
[Date].[Calendar].[Date].&[20060301]
:
[Date].[Calendar].[Date].&[20070308]
SET [Set2] AS
[Date].[Calendar].[Date].&[20070308]
:
[Date].[Calendar].[Date].&[20080315]
MEMBER [Date].[Calendar].[All].[Set1Agg] AS
aggregate([Set1])
MEMBER [Date].[Calendar].[All].[Set2Agg] AS
aggregate([Set2])
MEMBER [Date].[Calendar].[All].[x] AS
(
[Date].[Calendar].[All].[Set1Agg]
,[Measures].[Internet Sales Amount]
)
MEMBER [Date].[Calendar].[All].[y] AS
(
[Date].[Calendar].[All].[Set2Agg]
,[Measures].[Internet Sales Amount]
)
MEMBER [Date].[Calendar].[All].[x-y] AS
[Date].[Calendar].[All].[x] - [Date].[Calendar].[All].[y]
SELECT
{
[Date].[Calendar].[All].[x]
,[Date].[Calendar].[All].[y]
,[Date].[Calendar].[All].[x-y]
} ON 0
,[Product].[Category].[Category] ON 1
FROM [Adventure Works];
Reflecting against your code maybe something like the following:
WITH
SET [Set1] AS
[Created_Date.Created_Hir].[Created_On].[2014-04-01]
:
[Created_Date.Created_Hir].[Created_On].[2014-04-30]
SET [Set2] AS
[Created_Date.Created_Hir].[Created_On].[2014-03-01]
:
[Created_Date.Created_Hir].[Created_On].[2014-03-31]
MEMBER [Created_Date.Created_Hir].[All].[Set1Agg] AS
Aggregate([Set1])
MEMBER [Created_Date.Created_Hir].[All].[Set2Agg] AS
Aggregate([Set2])
MEMBER [Measures].[~Last30Days - Now] AS
(
[Created_Date.Created_Hir].[All].[Set1Agg]
,[Measures].[SomeMeasure]
)
MEMBER [Measures].[~Last60Days - Last30Days] AS
(
[Created_Date.Created_Hir].[All].[Set2Agg]
,[Measures].[SomeMeasure]
)
MEMBER [Measures].[~Measure] AS
([Measures].[~Last30Days - Now] - [Measures].[~Last60Days - Last30Days])
/
[Measures].[~Last60Days - Last30Days]
* 100
,format_string = '#,##0'
SET [~ROWS] AS
{
[Sales Order Attributes SO.Sales_order].[Sales Order ID].MEMBERS
}
SELECT
NON EMPTY
{
[Measures].[CONT_AMT_GROSS]
,[Measures].[CONT_AMT_NET]
,[Measures].[~Measure]
} ON COLUMNS
,NON EMPTY
[~ROWS] ON ROWS
FROM [SALES_ORDER]
WHERE
[~FILTER];
Let's say I have two simple dimensions:
Products - with id and name
Salesmen - with id and name
My fact table is named SALES and contains the ids of the abovementioned.
I need to produce a query that will show the names of salesmen who sold all of the given products.
This code solves the problem for two items X and Y:
SELECT
{} on 0,
EXISTS(
EXISTS(
{[Salesmen].[Name].MEMBERS},
{[Products].[Name].&[X]}
)
,{[Products].[Name].&[Y]}
)
ON 1
FROM [Test];
The other version is:
SELECT
{} on 0,
INTERSECT(
NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,([Products].[Name].&[X])
)
,NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,([Products].[Name].&[Y])
)
)
ON 1
FROM [Test];
However, this method becomes troublesome if the list of given products is large, for example - 100 random products..
Do you have a property member_key for the hierarchy [Products].[Name] ? We can test like this:
WITH
MEMBER [Measures].[Meas1] AS
[Products].[Name].CurrentMember.PROPERTIES("KEY ID")
MEMBER [Measures].[Meas2] AS
[Products].[Name].CurrentMember.MEMBER_Key
MEMBER [Measures].[Meas3] AS
[Products].[Name].CurrentMember.MEMBERvalue
select
{
[Measures].[Meas1]
,[Measures].[Meas2]
,[Measures].[Meas3]
} on COLUMNS,
[Products].[Name].MEMBERS on ROWS
FROM [Test];
Hopefully one of the custom measures gives you a value? I'll assume Meas2 is working (swap to a different one if Meas1 or Meas3 is returning numbers)
WITH
MEMBER [Measures].[Meas2] AS
[Products].[Name].CurrentMember.MEMBER_Key
SET [ProdsetA] AS
FILTER(
[Products].[Name].MEMBERS
,[Measures].[Meas2] <100
)
SET [ProdsetB] AS
FILTER(
[Products].[Name].MEMBERS
,[Measures].[Meas2] >500
)
SELECT
{} on 0,
INTERSECT(
NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,[ProdsetA]
)
,NONEMPTY(
{[Salesmen].[Name].MEMBERS}
,[ProdsetB]
)
)
ON 1
FROM [Test];
... the >100 and <500 are important. These are the criteria for the filter function to use. The custom set [ProdsetA] will only contain Products that have MEMBER_Key that are <100 whereas the custom set [ProdsetB] will only contain Products that have MEMBER_Key that are >500. You need to use the member values presented to you by the first script to decide what values 100 and 500 should be in your cube context (...I don't know the key values in your cube so just used 100 and 500 as placeholders)
I'd like to be able to search the [Employee Department] hierarchy - within any of it's levels using a string: the following does this ok and finds all members related to the string "Control"
Now I have tried to add a cross join so that I can always see the department name for each of the rows and then ORDER by the department. If the commented section is uncommented I unfortunately get a full cartesian product - I only want the departments in the context of the members found by the filter - is this possible?
WITH
MEMBER [Measures].[LevelName] AS
[Employee].[Employee Department].Level.Name
MEMBER [Measures].[LevelNumber] AS
[Employee].[Employee Department].Level.Ordinal
SET [Set_TargetEmp] AS
{
FILTER(
[Employee Department].AllMembers,
(
InStr(
1,
[Employee].[Employee Department].currentmember.name,
"Control") <> 0
)
)
}
SELECT
// ORDER(
// [Department].members,
// [Department].[Department].MEMBERVALUE
// )
// *
ORDER(
DESCENDANTS(
[Set_TargetEmp],
[Employee].[Employee Department].[Department],
SELF_BEFORE_AFTER
),
[Measures].[LevelNumber],
BASC
) as X
ON 1,
{
[Measures].[LevelName],
[Measures].[LevelNumber]
} ON 0
FROM [Adventure Works]
Assuming you use Department the Department dimension, and the Employee Department is in a different dimension named Employee, you get a cross product. Analysis Services only applies "autoexists" within the same dimension. Across dimensions, you must apply this logic explicitly like this:
ORDER(
Exists([Employee].[Department Name].[Department Name].members,
[Set_TargetEmp]
),
[Department].[Department].MEMBERVALUE
)
for the commented block in your code should deliver what you want.
In case you have more than one measure group that relate to both the department and the employee dimensions, you should state the name of the measure group to use as the third argument of Exists. This is a string argument, hence this name should be included in quotes.
I'm using the following but i think there's probably a much simpler method of excluding the All members from the results?
WITH
SET [Non_All_Distributors] AS
{FILTER(
[Distributor Name].members,
(InStr(1, [Distributor Name].CurrentMember.NAME, "All") = 0)
)}
SET [Non_All_Countries] AS
{FILTER(
[Geography Country].members,
(InStr(1, [Geography Country].CurrentMember.NAME, "All") = 0)
)}
SELECT
NON EMPTY
[Dimension].[Hierarchy].DEFAULTMEMBER
ON COLUMNS,
NON EMPTY
[Non_All_Distributors]
*
[Non_All_Countries]
*
Tail([Date].[Date - Calendar Month].[Calendar Day].Members,60)
*
{
[Measures].[Revenue],
[Measures].[NumClients]
}
ON ROWS
FROM [OURCUBE]
Just use
SELECT
NON EMPTY
[Dimension].[Hierarchy].DEFAULTMEMBER
ON COLUMNS,
NON EMPTY
[dimension of Distributor Name].[Distributor Name].[Distributor Name].Members
*
[dimension of Geography Country].[Geography Country].[Geography Country].Members
*
Tail([Date].[Date - Calendar Month].[Calendar Day].Members,60)
*
{
[Measures].[Revenue],
[Measures].[NumClients]
}
ON ROWS
FROM [OURCUBE]
There is no need to define sets here. you can directly state the distributor and country members in the rows clause.
By repeating the attribute name, you restrict the attribute hierarchy - which you refer to by [dim].[attrib name] to the level below the All member, which happens to have the same name as the attribute again. An attribute hierarchy has two levels: level 0 contains the 'All' member and level 1 all the members of the attribute. (This is true only if you did not do special configurations like setting the attribute as non aggregateabable, but I assume the standard case, as you have All members in your hierarchies.
Apart from being more simple, this statement will run much faster, as Filter is a real performance killer in many cases.
I would use the Descendants function and the AFTER option as following; this way you get all the members of the hierarchy below the all member:
select
[Measures].[Amount] on 0,
Descendants([Customers].[Geography].[All], 1, AFTER ) on 1
from [Sales]
(edited: with a request working with MSAS Adv. Works : removed the distance param)
select
Measures].[Order Count] on 0,
Descendants( [Geography].[Geography].[All], , AFTER ) on 1
from [Adventure Works]