SQL to MDX conversion - mdx

I have this where clause in sql language:
where (cond1=1 or cond2=1) and cond3=1
How can I get this result in MDX with the slicing(condition into the where)?
{[cond1].&[1],[cond2].&[1]} /*and*/ {[cond3].&[1]}
Thanks

Try to use a subcube:
Select
-- YOUR SELECTED MEASURES AND DIMENSIONS
From
(
Select
{[cond1].&[1],[cond2].&[1]} on 0
,{[cond3].&[1]} on 1
-- ,{more slices} on x
From [CubeName]
)
Hope this help!

You can use subcube expression as stated above, but this is not the only option. If you use subcube, you would increase query performance greatly (assuming the fact you don't perform crossjoins in it).
You can also use general WHERE keyword after last expression that returns cube:
select
{ .. } on 0,
{ .. } on 1
from (select { [Dim1].[X].allmembers } on 0)
where ([Dim2].[Y].&[Y1])
Or:
select
{ .. } on 0,
{ .. } on 1
from (select { [Dim1].[X].allmembers } on 0)
where {[DimTime].[Time].[Year].&[2001] : [DimTime].[Time].[Year].&[2015]}
This is applied at the end of execution, which means performance may decrease. However, if you need to apply external filter to all axis, this is the option you need.
Another way to filter member values is using tuple expressions:
with member LastDateSale as ( (Tail(EXISTING [DimTime].[Time].[Dates].members,1), [Measures].[ActualSales]) )
This will take your DimTime axis, apply external filter, get the last element from it and calculate [ActualSales] for it, if possible.

Related

Add array of other records from the same table to each record

My project is a Latin language learning app. My DB has all the words I'm teaching, in the table 'words'. It has the lemma (the main form of the word), along with the definition and other information the user needs to learn.
I show one word at a time for them to guess/remember what it means. The correct word is shown along with some wrong words, like:
What does Romanus mean? Greek - /Roman/ - Phoenician - barbarian
What does domus mean? /house/ - horse - wall - senator
The wrong options are randomly drawn from the same table, and must be from the same part of speech (adjective, noun...) as the correct word; but I am only interested in their lemma. My return value looks like this (some properties omitted):
[
{ lemma: 'Romanus', definition: 'Roman', options: ['Greek', 'Phoenician', 'barbarian'] },
{ lemma: 'domus', definition: 'house', options: ['horse', 'wall', 'senator'] }
]
What I am looking for is a more efficient way of doing it than my current approach, which runs a new query for each word:
// All the necessary requires are here
class Word extends Model {
static async fetch() {
const words = await this.findAll({
limit: 10,
order: [Sequelize.literal('RANDOM()')],
attributes: ['lemma', 'definition'], // also a few other columns I need
});
const wordsWithOptions = await Promise.all(words.map(this.addOptions.bind(this)));
return wordsWithOptions;
}
static async addOptions(word) {
const options = await this.findAll({
order: [Sequelize.literal('RANDOM()')],
limit: 3,
attributes: ['lemma'],
where: {
partOfSpeech: word.dataValues.partOfSpeech,
lemma: { [Op.not]: word.dataValues.lemma },
},
});
return { ...word.dataValues, options: options.map((row) => row.dataValues.lemma) };
}
}
So, is there a way I can do this with raw SQL? How about Sequelize? One thing that still helps me is to give a name to what I'm trying to do, so that I can Google it.
EDIT: I have tried the following and at least got somewhere:
const words = await this.findAll({
limit: 10,
order: [Sequelize.literal('RANDOM()')],
attributes: {
include: [[sequelize.literal(`(
SELECT lemma FROM words AS options
WHERE "partOfSpeech" = "options"."partOfSpeech"
ORDER BY RANDOM() LIMIT 1
)`), 'options']],
},
});
Now, there are two problems with this. First, I only get one option, when I need three; but if the query has LIMIT 3, I get: SequelizeDatabaseError: more than one row returned by a subquery used as an expression.
The second error is that while the code above does return something, it always gives the same word as an option! I thought to remedy that with WHERE "partOfSpeech" = "options"."partOfSpeech", but then I get SequelizeDatabaseError: invalid reference to FROM-clause entry for table "words".
So, how do I tell PostgreSQL "for each row in the result, add a column with an array of three lemmas, WHERE existingRow.partOfSpeech = wordToGoInTheArray.partOfSpeech?"
Revised
Well that seems like a different question and perhaps should be posted that way, but...
The main technique remains the same. JOIN instead of sub-select. The difference being generating the list of lemmas for then piping then into the initial query. In a single this can get nasty.
As single statement (actually this turned out not to be too bad):
select w.lemma, w.defination, string_to_array(string_agg(o.defination,','), ',') as options
from words w
join lateral
(select defination
from words o
where o.part_of_speech = w.part_of_speech
and o.lemma != w.lemma
order by random()
limit 3
) o on 1=1
where w.lemma in( select lemma
from words
order by random()
limit 4 --<<< replace with parameter
)
group by w.lemma, w.defination;
The other approach build a small SQL function to randomly select a specified number of lemmas. This selection is the piped into the (renamed) function previous fiddle.
create or replace
function exam_lemma_definition_options(lemma_array_in text[])
returns table (lemma text
,definition text
,option text[]
)
language sql strict
as $$
select w.lemma, w.definition, string_to_array(string_agg(o.definition,','), ',') as options
from words w
join lateral
(select definition
from words o
where o.part_of_speech = w.part_of_speech
and o.lemma != w.lemma
order by random()
limit 3
) o on 1=1
where w.lemma = any(lemma_array_in)
group by w.lemma, w.definition;
$$;
create or replace
function exam_lemmas(num_of_lemmas integer)
returns text[]
language sql
strict
as $$
select string_to_array(string_agg(lemma,','),',')
from (select lemma
from words
order by random()
limit num_of_lemmas
) ll
$$;
Using this approach your calling code reduces to a needs a single SQL statement:
select *
from exam_lemma_definition_options(exam_lemmas(4))
order by lemma;
This permits you to specify the numbers of lemmas to select (in this case 4) limited only by the number of rows in Words table. See revised fiddle.
Original
Instead of using a sub-select to get the option words just JOIN.
select w.lemma, w.definition, string_to_array(string_agg(o.definition,','), ',') as options
from words w
join lateral
(select definition
from words o
where o.part_of_speech = w.part_of_speech
and o.lemma != w.lemma
order by random()
limit 3
) o on 1=1
where w.lemma = any(array['Romanus', 'domus'])
group by w.lemma, w.definition;
See fiddle. Obviously this will not necessary produce the same options as your questions provides due to random() selection. But it will get matching parts of speech. I will leave translation to your source language to you; or you can use the function option and reduce your SQL to a simple "select *".

SimeReplacing WeekOfYear Dynamically

I am using copy activity in ADF in which i have following pseudo query:
SELECT
{
[Measures].[**************],
[Measures].[**************],
[Measures].[**************]
} ON COLUMNS,
NON EMPTY
{
[0CALWEEK].[LEVEL01].MEMBERS
}
DIMENSION PROPERTIES MEMBER_CAPTION, MEMBER_UNIQUE_NAME ON ROWS
FROM cubeName/ReportName
SAP VARIABLES [SAP_VARIABLE_NAME]
INCLUDING [0CALWEEK].[201905]
In the above i want to replace '201905' dynamically,there is no current function availabe to get WeekOfYear in ADF Expressions and functions OR can i use MDX Query to generate WeekOfYear
Take a look at this example how it changes value for a member value. Please note I have answerd if from phone so some syntax issue might exist.
With member measures.t
As
Case when
[0CALWEEK].[LEVEL01]. currentmember.name="'201905"
Then 1
Else
0
End
SELECT
{
[Measures].[t]
} ON COLUMNS,
NON EMPTY
{
[0CALWEEK].[LEVEL01].MEMBERS
} ON ROWS
FROM cubeName/ReportName

Making SPARQL FILTER conditional

How to make a FILTER() conditional? This is the relevant part of my query:
SELECT *
WHERE {
VALUES (?open) {$U2}
?URI_OPP CSV:id_opportunita ?ID_OPP.
OPTIONAL { ?URI_OPP CSV:data_scadenza ?DATA_S }
FILTER ((NOW() - xsd:datetime(?DATA_S)) > 0)
}
It gets $U2 as a value for ?open. I want to apply the filter if ?open = 1, and not to apply it in all other cases.
While IF() works on the query results, I don't know what to use to switch off parts of the query itself.
Since the above commented never answered, I will:
FILTER(
(?open != 1) ||
((NOW() - xsd:datetime(?DATA_S)) > 0)
)

Hive access previous row value

I have the same issue mentioned
here
However, the problem is on Hive database. When I try the solution on my table that looks like
Id Date Column1 Column2
1 01/01/2011 5 5 => Same as Column1
2 02/01/2011 2 18 => (1 + (value of Column2 from the previous row)) * (1 + (Value of Column1 from the current row)) i.e. (1+5)*(1+2)
3 03/01/2011 3 76 => (1+18)*(1+3) = 19*4
I get the error
FAILED: SemanticException Recursive cte cteCalculation detected (cycle: ctecalculation -> cteCalculation).
What is the workaround possible in this case
You will have to write a UDF for this.
Below you can see a very (!!) simplified UDF for what you need.
The idea is to store the value from the previous execution in a variable inside the UDF and each time return (stored_value+1)*(current_value+1) and then store it for the next line.
You need to take care of the first value to get, so there is a special case for that.
Also, you have to pass the data ordered to the function as it simply goes line by line and performs what you need without considering any order.
You have to add your jar and create a function, lets call it cum_mul.
The SQL will be :
select id,date,column1,cum_mul(column1) as column2
from
(select id,date,column1 from myTable order by id) a
The code for the UDF :
import org.apache.hadoop.hive.ql.exec.UDF;
public class cum_mul extends UDF {
private int prevValue;
private boolean first=true;
public int evaluate(int value) {
if (first) {
this.prevValue = value;
first = false;
return value;
}
else {
this.prevValue = (this.prevValue+1)*(value+1);
return this.prevValue;
}
}
}
Hive common table expression (CTE) works as a query level temp-table (a syntax sugar) that is accessible within the whole SQL.
Recursive query is not supported because it introduces multiple stages with massive I/O, which is something that the underlying execution and storage engine not good at. In fact, Hive strictly prohibit recursive references for CTEs and views. Hence the error you got.

Parameterizing Asymmetric Set in MDX?

I upgraded to SQL server 2008 R2 from 2005, and now this query is no longer working(although I don't rule out something I did being the cause). I have simplified the names/query to demonstrate the issue:
SELECT
NON EMPTY
{
[BizDim].[County].[County]
* [BizDim].[name].[name]
}
ON COLUMNS,
{
[Biz Line Type Dimension].[Line Number].[Line Number]
* [Biz Line Type Dimension].[Display Name].[Display Name]
}
ON ROWS
FROM [TPS Data View]
Where (
STRTOSET("{[BizDim].[County ID].&[16]}", CONSTRAINED)
,STRTOSET("{([BizDim].[Corp].[Corp].ALLMEMBERS,[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].&[x]),([BizDim].[Corp].[Corp].&[x],[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].ALLMEMBERS)}")
)
Essentially this is a logical OR saying if column Corp == 'x' OR HQ == 'x' then include it in the result. This is known as an assymmetric(sic) set.
The above gives the error:
The Tuple function expects a tuple expression for the 3 argument. A tuple set expression was used.
I can remove the STRTOSET function and it works perfectly:
Where (
STRTOSET("{[BizDim].[County ID].&[16]}", CONSTRAINED)
,{([BizDim].[Corp].[Corp].ALLMEMBERS,[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].&[x]),([BizDim].[Corp].[Corp].&[x],[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].ALLMEMBERS)}
)
However, this is no good because the actual query is parameterized, so it must work with a STRTO* function:
Where (
STRTOSET(#Counties, CONSTRAINED)
,STRTOSET(#BizTypes)
)
I have tried STRTOTUPLE and get the same error.
I could build the query dynamically but I'd rather avoid taking that risk, especially given that it worked fine before with a parameter.
So the question is, how to get this assymmetric set to work as a parameter again in SQL Server 2008 R2 SSAS?
Update:
Note that this eliminates the error by replacing the keys will ALLMEMBERS, but doesn't actually filter anything so it is useful only to show in general my syntax doesn't seem to be bad:
Where (
STRTOSET("{[BizDim].[County ID].&[16]}", CONSTRAINED)
,{([BizDim].[Corp].[Corp].ALLMEMBERS,[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].ALLMEMBERS),([BizDim].[Corp].[Corp].ALLMEMBERS,[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].ALLMEMBERS)}
)
I did manage to get this working in a less dynamic way, but quite annoying. Basically my filter would need to be divided into many different parameters because I would need a STRTOSET call for each one:
Where (
STRTOSET("{[BizDim].[County ID].&[16]}", CONSTRAINED)
,{
STRTOSET("([BizDim].[Corp].[Corp].ALLMEMBERS,[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].&[x])")
,STRTOSET"([BizDim].[Corp].[Corp].&[x],[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].ALLMEMBERS)")
}
)
[edited after comments]
Where
STRTOSET("{[BizDim].[County ID].&[16]}", CONSTRAINED)
* STRTOSET("{([BizDim].[Corp].[Corp].ALLMEMBERS,[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].&[x]),([BizDim].[Corp].[Corp].&[x],[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].ALLMEMBERS)}")
They might be an ambiguity with the ( x, y, z ) notation which is either a tuple or a parenthesis operator; e.g., ( {}, {} ) is a crossjoin.
Perhaps you need an explicit wrapping into a set :
{ [BizDim].[HQ].[HQ].&[x] }
Or replace:
([BizDim].[Corp].[Corp].ALLMEMBERS,[BizDim].[Local].[Local].ALLMEMBERS,[BizDim].[HQ].[HQ].&[x])
with an explicit crossjoin:
{ [BizDim].[Corp].[Corp].ALLMEMBERS * [BizDim].[Local].[Local].ALLMEMBERS * { [BizDim].[HQ].[HQ].&[x] } }
Hope that helps.