How should I write an MDX Filter statement with multiple OR conditions efficiently? - mdx

In SQL you can compare a field against a set in the form
[Foo] In {"Bar1", "Bar2", ... , "BarN"}
However I'm having trouble working out how to move a filter expression into something like this. That is, for now, I end up with:
Filter(
[MyHierarchy].[Foo].Members,
[MyHierarchy].CurentMember.Name = "1"
OR [MyHierarchy].CurentMember.Name = "2"
...
OR [MyHierarchy].CurentMember.Name = "N"
)
Since I have 20-30 comparisons, and a moderate chance of the heirarchy name changing, I'd much rather maintain a set and a hierarchy name than a long expression. Is there any way to accomplish this?
Worth bearing in mind that the context is an Excel CubeSet function, so I'm a little limited in terms of defining my own members in the WITH clause.

Assuming you have a set named SelectedMembers, you could use
Intersect([MyHierarchy].[Foo].Members, [SelectedMembers])
You could of course also code this directly, i. e.
Intersect([MyHierarchy].[Foo].Members,
{
[MyHierarchy].[Foo].[1],
[MyHierarchy].[Foo].[2],
...
[MyHierarchy].[Foo].[N]
}
)
But it might be more convenient to have the set already defined in the cube calculation script - if that is possible.

Related

Check if an item exists in MDX named set

I want to create a named set for two football teams. I'm not exactly sure what the syntax is, but what I have thus far is:
EXISTS(
[Team].[Team],
{[Team].[Team].&[BAL], [Team].[Team].&[DEN]}
)
In other words, I want to create a Named set if the team is named "BAL" or "DEN". What would be the proper way to write this expresion?
The following query syntax works for me, but I'd like to translate this into "creating a named set" in BIDS:
WITH SET[FavoriteTeams] AS{
[Team].[Team].&[DEN],
[Team].[Team].&[BAL]
}
SELECT
[Measures].[Net Wins] on 0,
[FavoriteTeams] on 1
FROM [NFL]
It seems perhaps it is as simple as just typing that in manually to the expression?
Sets are an important concept in MDX. A set is a collection of members from the same dimension and hierarchy. The hierarchy can be an attribute hierarchy or a user-defined hierarchy.
set = {membre1,member 2 ..}
the simpler the set expression the better it is.
So you should use the second expression
{
[Team].[Team].&[DEN],
[Team].[Team].&[BAL]
}
In your case no need to use the exists function since the members are defined.
we use exists in some setuations like we want to get all the cities of a specific region.
EXISTS([City].[City], [region].[region].[Region].&[1])
Visit : Microsoft.doc

Use String for IF statement conditions

I'm hoping someone can help answer my question, perhaps with an idea of where to go or whether what I'm trying to do is not possible with the way I want to do it.
I've been asked to write a set of rules based on the data held by our ERP form components or variables.
Unfortunately, these components and variables cannot be accessed or used outside of the ERP, so I can't use SQL to query the values and then build some kind of SQL query.
They'd like the ability to put statements like these:
C(MyComponentName) = C(MyOtherComponentName)
V(MyVariableName) > 16
(C(MyComponentName) = "") AND V(MyVariableName) <> "")
((C(MyComponentName) = "") OR C(MyOtherComponentName) = "") AND V(MyVariableName) <> "")
This should be turned into some kind of query which gets the value of MyComponentName and MyOtherComponentName and (in this case) compares them for equality.
They don't necessarily want to just compare for equality, but to be able to determine whether a component / variable value is greaterthan or lessthan etc.
Basically it's a free-form statement that gets converted into something similar to an IF statement.
I've tried this:
Sub TestCondition()
Dim Condition as string = String.Format("{0} = {1}", _
Component("MyComponent").Value, Component("MyOtherComponent").Value)
If (Condition) Then
' Do Something
Else
' Do Something Else
End If
End Sub
Obviously, this does not work and I honestly didn't think it would be so simple.
Ignoring the fact that I'd have to parse the line, extract the required operators, the values from components or variables (denoted by a C or V) - how can I do this?
I've looked at Expression Trees but these were confusing, especially as I'd never heard of them, let alone used them. (Is it possible to create an expression tree for dynamic if statements? - This link provided some detail on expression trees in C#)
I know an easier way to solve this might be to simply populate the form with a multitude of drop-down lists, so users pick what they want from lists or fill in a text box for a specific search criteria.
This wouldn't be a simple matter as the ERP doesn't allow you to dynamically create controls on its forms. You have to drag each component manually and would be next to useless as we'd potentially want at least 1 rule for every form we have (100+).
I'm either looking for someone to say you cannot do this the way you want to do it (with a suitable reason or suggestion as to how I could do it) that I can take to my manager or some hints, perhaps a link or 2 pointing me in the right direction.
If (Condition) Then
This is not possible. There is no way to treat data stored in a string as code. While the above statement is valid, it won't and can't function the way you want it to. Instead, Condition will be evaluated as what it is: a string. (Anything that doesn't boil down to 0 is treated as True; see this question.)
What you are attempting borders on allowing the user to type code dynamically to get a result. I won't say this is impossible per se in VB.Net, but it is incredibly ambitious.
Instead, I would suggest clearly defining what your application can and can't do. Enumerate the operators your code will allow and build code to support each directly. For example:
Public Function TestCondition(value1 As Object, value2 As Object, op as string) As Boolean
Select Case op
Case "="
Return value1 = value2
Case "<"
Return value1 < value2
Case ">"
Return value1 > value2
Case Else
'Error handling
End Select
End Function
Obviously you would need to tailor the above to the types of variables you will be handling and your other specific needs, but this approach should give you a workable solution.
For my particular requirements, using the NCalc library has enabled me to do most of what I was looking to do. Easy to work with and the documentation is quite extensive - lots of examples too.

Regex match SQL values string with multiple rows and same number of columns

I tried to match the sql values string (0),(5),(12),... or (0,11),(122,33),(4,51),... or (0,121,12),(31,4,5),(26,227,38),... and so on with the regular expression
\(\s*\d+\s*(\s*,\s*\d+\s*)*\)(\s*,\s*\(\s*\d+\s*(\s*,\s*\d+\s*)*\))*
and it works. But...
How can I ensure that the regex does not match a values string like (0,12),(1,2,3),(56,7) with different number of columns?
Thanks in advance...
As i mentioned in comment to the question, the best way to check if input string is valid: contains the same count of numbers between brackets, is to use client side programm, but not clear SQL.
Implementation:
List<string> s = new List<string>(){
"(0),(5),(12)", "(0,11),(122,33),(4,51)",
"(0,121,12),(31,4,5),(26,227,38)","(0,12),(1,2,3),(56,7)"};
var qry = s.Select(a=>new
{
orig = a,
newst = a.Split(new string[]{"),(", "(", ")"},
StringSplitOptions.RemoveEmptyEntries)
})
.Select(a=>new
{
orig = a.orig,
isValid = (a.newst
.Sum(b=>b.Split(new char[]{','},
StringSplitOptions.RemoveEmptyEntries).Count()) %
a.newst.Count()) ==0
});
Result:
orig isValid
(0),(5),(12) True
(0,11),(122,33),(4,51) True
(0,121,12),(31,4,5),(26,227,38) True
(0,12),(1,2,3),(56,7) False
Note: The second Select statement gets the modulo of sum of comma instances and the count of items in string array returned by Split function. If the result isn't equal to zero, it means that input string is invalid.
I strongly believe there's a simplest way to achieve that, but - at this moment - i don't know how ;)
:(
Unless you add some more constraints, I don't think you can solve this problem only with regular expressions.
It isn't able to solve all of your string problems, just as it cannot be used to check that the opening and closing of brackets (like "((())()(()(())))") is invalid. That's a more complicated issue.
That's what I learnt in class :P If someone knows a way then that'd be sweet!
I'm sorry, I spent a bit of time looking into how we could turn this string into an array and do more work to it with SQL but built in functionality is lacking and the solution would end up being very hacky.
I'd recommend trying to handle this situation differently as large scale string computation isn't the best way to go if your database is to gradually fill up.
A combination of client and serverside validation can be used to help prevent bad data (like the ones with more numbers) from getting into the database.
If you need to keep those numbers then you could rework your schema to include some metadata which you can use in your queries, like how many numbers there are and whether it all matches nicely. This information can be computed inexpensively from your server and provided to the database.
Good luck!

Constructing a recursive compare with SQL

This is an ugly one. I wish I wasn't having to ask this question, but the project is already built such that we are handling heavy loads of validations in the database. Essentially, I'm trying to build a function that will take two stacks of data, weave them together with an unknown batch of operations or comparators, and produce a long string.
Yes, that was phrased very poorly, so I'm going to give an example. I have a form that can have multiple iterations of itself. For some reason, the system wants to know if the entered start date on any of these forms is equal to the entered end date on any of these forms. Unfortunately, due to the way the system is designed, everything is stored as a string, so I have to format it as a date first, before I can compare. Below is pseudo code, so please don't correct me on my syntax
Input data:
'logFormValidation("to_date(#) == to_date(^)"
, formname.control1name, formname.control2name)'
Now, as I mentioned, there are multiple iterations of this form, and I need to loop build a fully recursive comparison (note: it may not always be typical boolean comparisons, it could be internally called functions as well, so .In or anything like that won't work.) In the end, I need to get it into a format like below so the validation parser can read it.
OR(to_date(formname.control1name.1) == to_date(formname.control2name.1)
,to_date(formname.control1name.2) == to_date(formname.control2name.1)
,to_date(formname.control1name.3) == to_date(formname.control2name.1)
,to_date(formname.control1name.1) == to_date(formname.control2name.2)
:
:
,to_date(formname.control1name.n) == to_date(formname.control2name.n))
Yeah, it's ugly...but given the way our validation parser works, I don't have much of a choice. Any input on how this might be accomplished? I'm hoping for something more efficient than a double recursive loop, but don't have any ideas beyond that
Okay, seeing as my question is apparently terribly unclear, I'm going to add some more info. I don't know what comparison I will be performing on the items, I'm just trying to reformat the data into something useable for ANY given function. If I were to do this outside the database, it'd look something like this. Note: Pseudocode. '#' is the place marker in a function for vals1, '^' is a place marker for vals2.
function dynamicRecursiveValidation(string functionStr, strArray vals1, strArray vals2){
string finalFunction = "OR("
foreach(i in vals1){
foreach(j in vals2){
finalFunction += functionStr.replace('#', i).replace('^', j) + ",";
}
}
finalFunction.substring(0, finalFunction.length - 1); //to remove last comma
finalFunction += ")";
return finalFunction;
}
That is all I'm trying to accomplish. Take any given comparator and two arrays, and create a string that contains every possible combination. Given the substitution characters I listed above, below is a list of possible added operations
# > ^
to_date(#) == to_date(^)
someFunction(#, ^)
# * 2 - 3 <= ^ / 4
All I'm trying to do is produce the string that I will later execute, and I'm trying to do it without having to kill the server in a recursive loop
I don't have a solution code for this but you can algorithmically do the following
Create a temp table (start_date, end_date, formid) and populate it with every date from any existing form
Get the start_date from the form and simply:
SELECT end_date, form_id FROM temp_table WHERE end_date = <start date to check>
For the reverse
SELECT start_date, form_id FROM temp_table WHERE start_date = <end date to check>
If the database is available why not let it do all the heavy lifting.
I ended up performing a cross product of the data, and looping through the results. It wasn't the sort of solution I really wanted, but it worked.

QTP, access to QC field by label

I want to update a custom user field in QC using the Label of field instead of the name
At the moment we are doing it this way
Set currentRun = QCUtil.CurrentRun
currentRun.Field("RN_USER_03") = 1
currentRun.Post
But I would like to do it this way
Set currentRun = QCUtil.CurrentRun
currentRun.Field("Data Rows Passed") = 4
currentRun.Post
But I can't find the method to do it with.
Any Ideas?
Implying all labels are unique (which I doubt..):
You could create a function which accepts a label, searches in QC's tables that define customized fields for the correct field definition, and returns the field name. Then use the function's result value as the indexed property's index.
Suppose that function would be called "GetNameOfLabel", then the Caller's code would look like:
Set currentRun = QCUtil.CurrentRun
currentRun.Field(GetNameOfLabel ("Data Rows Passed")) = 1
currentRun.Post
Of course, the function would not really be trivial, but easy enough after some digging in the QC data model and finding an efficient way to fetch the name from the DB via SQL.
Or, the function could look up the name in an array, or a dictionary, then you would have to maintain that dictionary, but you would not have to go to the database for each lookup.
Disadventages:
Scripts with the wrong label might be harder to be debug
If labels are not unique, it might be real "fun" to debug
If looking up on the DB:
All scripts slow down if you don't cache, or pre-load, SQL query results for those lookups;
complexity, as you have to do the right SQL query, and you depend on QC's data model in a quite peculiar way (usually a horror when you're upgrading)
If looking up in an array, or dictionary:
You either must maintain its initialization (bet other admin guys adding a cust field will forget that easily), or must "load" it from QC's table (which is a bit like the SQL solution above, and has the same downsides).
I'd go with the array/dictionary-initialized-from-db-idea. Or, if you can live with the constant idea already presented, that one is a good bet. Considering that there is no session-independent scope in QCs customizing scripts, the SQL access idea might really kill performance because it would have to be executed for every new user session. Which is why I, too, +1'd the constant idea.
Look at this:
Dim gFieldLabelToNameDICT: Set gFieldLabelToNameDICT = CreateObject("Scripting.Dictionary")
gFieldLabelToNameDICT.CompareMode = vbTextCompare
Function GetNameOfLabel (strFieldLabel)
' If it doesn't exist yet in fieldLabelToName dict -> search it using TDC and add it to the list to improve performance
If Not gFieldLabelToNameDICT.Exists(strFieldLabel) Then
Dim testSetFields As List
Dim testSetFields: Set testSetFields = QCUtil.QCConnection.Customization.Fields.Fields("RUN")
For Each aField in testSetFields
If aField.UserLabel = strFieldLabel Then
gFieldLabelToNameDICT.Item(strFieldLabel) = aField.ColumnName
End If
Next aField
End If
GetNameOfLabel = gFieldLabelToNameDICT.Item(strFieldLabel)
End Function
Maybe you shall want to add some more error handling, such us considering the case that the label is not found.