MDX : filter parents with children - mdx

I've got the following query :
SELECT
NON EMPTY { [Measures].[Mes] } ON COLUMNS,
NON EMPTY { [Dim].[Lev1].Members, [Dim].[Lev2].Members } ON ROWS
FROM [Cube]
Where Lev2 is the hierarchical child of Lev1.
That gives me the following result :
Lev1 | Lev2 | Mes
_________________
yes | 1 | 1
yes | 2 | 2
no | 3 | 3
no | 4 | 4
EDIT : Maybe this view is more relevant :
Dim | Mes
- yes | 3
1 | 1
2 | 2
- no | 7
3 | 3
4 | 4
What I want is to filter Lev1 with Lev2 = 2 or Lev2 = 4 to get the following result :
Lev1 | Mes
___________
yes | 2
no | 4
Is this is even possible?
I'm using Mondran and Olap4j.

It seems that Lev1 and Lev2 are attribute hierarchies. As these can be separate (like making up two columns of your row header of your first query), you also can split them between the row and the where axis:
SELECT
NON EMPTY { [Measures].[Mes] } ON COLUMNS,
NON EMPTY { [Dim].[Lev1].Members } ON ROWS
FROM [Cube]
WHERE { [Dim].[Lev2].[2], [Dim].[Lev2].[4] }

I think this is effectively the same as FrankPI's answer. Although this may work in your application:
SELECT
NON EMPTY
{ [Measures].[Mes] }
ON COLUMNS,
NON EMPTY
EXISTS(
{ [Dim].[Lev1].Members }
, { [Dim].[Lev2].[2], [Dim].[Lev2].[4] }
)
ON ROWS
FROM [Cube]
Maybe a subselect
SELECT
NON EMPTY
{ [Measures].[Mes] }
ON COLUMNS,
NON EMPTY
EXISTS(
{ [Dim].[Lev1].Members }
, { [Dim].[Lev2].[2], [Dim].[Lev2].[4] }
)
ON ROWS
FROM
(
SELECT { [Dim].[Lev2].[2], [Dim].[Lev2].[4] } ON 0
FROM [Cube]
)

I just discover the VisualTotals function which does the job well:
SELECT
NON EMPTY {[Measures].[Mt cheques]} ON COLUMNS,
NON EMPTY VisualTotals (hierarchize({
[Dim].[Lev1].Members,
[Dim].[yes].[2],
[Dim].[no].[4]
)}) ON ROWS
FROM [Cube]
Thanks for your help!

Related

Join members from different dimensions on rows in MDX

I have 4 separate dimensions I'm interested in: ( A, B, C date ).
Each dimension has multiple attribute hierarchies.
Each dimension theoretically maps to each other. C -> B -> A.
In other words, multiple members of B map to a single member in A and multiple members of C map to a single member of B.
Originally I had the following query which worked
SELECT
(
[Measures].[Count]
)
ON COLUMNS,
(
[A].[Id].[Id].MEMBERS,
FILTER
(
[A].[Name].[Name].MEMBERS,
LEFT([A].[Name].CURRENTMEMBER.NAME, 4) <> "test"
),
[A].[Start].[Start].MEMBERS,
[A].[Owner].[Owner].MEMBERS
)
ON ROWS
FROM
(
SELECT
(
{[A].[Start].&[2020-05-10] : [A].[Start].&[2020-05-25]}
)
ON COLUMNS
FROM [Model]
)
WHERE
(
{[date].[date].&[2020-05-10] : [date].[date].&[2020-05-25]},
{[B].[End].&[2020-05-25]:NULL},
[A].[Product].&[ASDF]
)
The output I was getting looked as follows:
A.id | A.Name | A.Owner | Count
----------------------------------------
1 | A | asdf | (null)
2 | B | asdf | 23
3 | C | asdd | (null)
4 | D | asdf | (null)
5 | E | qwer | 5067
6 | F | adfd | (null)
7 | G | wert | (null)
... | ... | .... | ...
25 | Y | werd | (null)
As you can see there are a lot of nulls in the data.
I now have additional requirement to filter only to "Enabled" members of the B.id hierarchy.
So in the WHERE clause I added the following line: [B].[Status].&[Enabled].
This did not change my output but I know it should because I have to table that I need mocked up in PowerBI and this condition eliminates a few members from the A.id hierarchy.
Tha new output should look something like this:
A.id | A.Name | A.Owner | Count
----------------------------------------
2 | B | asdf | 23
4 | D | asdf | (null)
5 | E | qwer | 5067
7 | G | wert | (null)
... | ... | .... | ...
25 | Y | werd | (null)
As you can see, some nulls should still be there because they have "Enabled" B.Id members mapped to them.
I then tried to add [B].[id].[id].MEMBERS and [B].[Status].[Status].MEMBERS on the rows to see what the relationship is and why certain members of A.id are not being dropped. I did that as follows:
(
[A].[Id].[Id].MEMBERS,
FILTER
(
[A].[Name].[Name].MEMBERS,
LEFT([A].[Name].CURRENTMEMBER.NAME, 4) <> "test"
),
[A].[Start].[Start].MEMBERS,
[A].[Owner].[Owner].MEMBERS,
[B].[id].[id].MEMBERS,
[B].[Status].[Status].MEMBERS
)
ON ROWS
But this showed every single member of A mapped with every single member of B. Basically a crossjoin. This is not what I need. Like I mentioned, there are unique members in B that map to one member in A. I did a lot of googling and came across a LINKMEMBER() function but this does not seem to work for the implementation I need. Any help or advice is appreciated.
The current query I am running is below. I have tried adding the commented [B].[Status].&[Enabled] to both the WHERE clause and ON ROWS but it was giving me the same results as always. I also tried to use the FILTER function and filter to only [B].[Status].CURRENTMEMBER.NAME = "Enabled" but that produced an empty table with no output.
SELECT
(
[Measures].[Count]
)
ON COLUMNS,
ORDER(
(
--[B].[Status].&[Enabled],
[A].[Id].Children,
FILTER
(
[A].[Name].Children,
LEFT([A].[Name].CURRENTMEMBER.NAME, 4) <> "test"
),
[A].[Start].Children,
[A].[Owner].Children
),
[A].[Start].CurrentMember.Member_Key,
BASC
)
ON ROWS
FROM
(
SELECT
(
{[A].[Start].&[2020-05-21] : [A].[Start].&[2020-05-27]}
)
ON COLUMNS
FROM [Model]
)
WHERE
(
{[date].[date].&[2020-05-21] : [date].[date].&[2020-05-27]},
--[B].[Status].&[Enabled],
[A].[Product].&[ASDF]
)
Im fairly new to MDX so I apologies for the extensive explanation.
Welcome to Stackoverflow and MDX. The problem you are facing is address by using non empty.
In MDX if you write (DimA.Attribute1.members,DimB.Attribute1.members), it means you are asking for a cross join. To ensure that only those combination are returned that are valid you have to use non empty. Try your modified query below
SELECT
(
[Measures].[Count]
)
ON COLUMNS,
non empty(
[A].[Id].[Id].MEMBERS,
FILTER
(
[A].[Name].[Name].MEMBERS,
LEFT([A].[Name].CURRENTMEMBER.NAME, 4) <> "test"
),
[A].[Start].[Start].MEMBERS,
[A].[Owner].[Owner].MEMBERS
)
ON ROWS
FROM
(
SELECT
(
{[A].[Start].&[2020-05-10] : [A].[Start].&[2020-05-25]}
)
ON COLUMNS
FROM [Model]
)
WHERE
(
{[date].[date].&[2020-05-10] : [date].[date].&[2020-05-25]},
{[B].[End].&[2020-05-25]:NULL},
[A].[Product].&[ASDF],[B].[Status].&[Enabled]
)
One thing that needs to be remembered is that this happens we you are using attribute of diffrent dimensions, if you have the same dimensions its handled automatically. Example (Dim1.attribute1.members, Dim1.attribute2.members), This will only returns datapoints that exist.
Try the Query below.
SELECT
(
[Measures].[Count]
)
ON COLUMNS,
([B].[Status].&[Enabled],
[A].[Id].[Id].MEMBERS,
FILTER
(
[A].[Name].[Name].MEMBERS,
LEFT([A].[Name].CURRENTMEMBER.NAME, 4) <> "test"
),
[A].[Start].[Start].MEMBERS,
[A].[Owner].[Owner].MEMBERS
)
ON ROWS
FROM
(
SELECT
(
{[A].[Start].&[2020-05-10] : [A].[Start].&[2020-05-25]}
)
ON COLUMNS
FROM [Model]
)
WHERE
(
{[date].[date].&[2020-05-10] : [date].[date].&[2020-05-25]},
{[B].[End].&[2020-05-25]:NULL},
[A].[Product].&[ASDF]
)

How can I SELECT rows with MAX(Column value) in DQL?

I can not get this query in a symfony2 project that I have.
My Table:
id course datetime numOrden
---|-----|------------|--------
1 | 1º | 04/11/2016 | 1
2 | 2º | 04/11/2016 | 2
5 | 3º | 04/11/2016 | 5
3 | 4º | 03/11/2016 | 4
4 | 5º | 03/11/2016 | 3
I need to get the course whose value in the "numOrden" column is the maximum( in this case it would be the 3rd course). For this I have used the following query in Doctrine2:
public function findCourse()
{
return $this->getEntityManager()->createQuery(
'SELECT c FROM BackendBundle:Curso c WHERE c.numOrden in (SELECT max(c.numOrden) FROM BackendBundle:Curso )')
->getResult();
}
Or
public function findCourse()
{
return $this->getEntityManager()->createQuery(
'SELECT c FROM Bundle:Course c WHERE c.numOrden=(SELECT max(c.numOrden) FROM Bundle:Course )')
->getResult();
}
But it shows the following error:
[Syntax Error] line 0, col -1: Error: Expected Doctrine\ORM\Query\Lexer::T_CLOSE_PARENTHESIS, got end of string. (500 Internal Server Error)
Try using another alias in the subselect as:
public function findCourse()
{
return $this->getEntityManager()->createQuery(
'SELECT c FROM Bundle:Course c WHERE c.numOrden=(SELECT max(co.numOrden) FROM Bundle:Course co )')
->getResult();
}
Hope this help

Orientdb query child

Is there a way with Orientdb 2.1.11 (document database) to get the EmebeddedList
Here is the class structure
{
"#class":"Quote",
"number":"Q1",
"details":[{
"code":"123",
"price":10
},{
"code":"456",
"price":20
}
]
},{
"#class":"Quote",
"number":"Q2",
"details":[{
"code":"789",
"price":15
},{
"code":"951",
"price":25
}
]
}
I would like a query that will return the following :
number| code | price
------|------|------
Q1 | 123 | 10
Q1 | 456 | 20
Q2 | 789 | 15
Q2 | 951 | 25
I have replicated your structure
and I have used this query
select number, details.code as code, details.price as price from (select prop.number as number, prop.details as details from (select prop from test unwind prop) unwind details)
Hope it helps

Unique values in Sequelize

I use Sequelize ORM for Node.js. I need to get lines with unique values in certain column. Example table:
id | name | group
-----------------
1 | One | 2
2 | Two | 1
3 | Three| 2
4 | Four | 3
5 | Five | 1
Query for column group and result:
id | name | group
-----------------
1 | One | 2
2 | Two | 1
4 | Four | 3
Lines One, Two and Four was the first who had unique group values. How to make it in Sequelize?
A Sequelize raw query is one way of getting out the rows that you want:
/*
var sql =
SELECT r.id,
r.name,
r.groupnum
FROM s04.row r
JOIN
(SELECT min(id) AS id,
groupnum
FROM s04.row
GROUP BY groupnum) s
ON r.id = s.id
*/
return sq.query(sql, { type: sq.QueryTypes.SELECT});
The resulting promise will resolve to a JSON array:
[
{
"id": 1,
"name": "One",
"groupnum": 2
}
...
]
If you then needed to work with these rows as Instances you can call build on each element of the array:
Model.build({ /* attributes-hash */ }, { isNewRecord: false })
See here for an example. If I find a way of doing this via Sequelize function calls (aggregate, find*, etc) that isn't too hideous I'll also post that here as a separate answer.

PostgresQL SQL: Converting results to array

The query below:
SELECT i_adgroup_id, i_category_id
FROM adgroupcategories_br
WHERE i_adgroup_id IN
(
SELECT i_adgroup_id
FROM adgroupusers_br
WHERE i_user_id = 103713
)
GROUP BY i_adgroup_id, i_category_id;
Gives me results like this:
i_adgroup_id integer | i_category_id smallint
---------------------|-----------------------
15938 | 2
15938 | 3
15938 | 4
15942 | 1
15942 | 2
What I want is results like this:
i_adgroup_id integer | i_category_id smallint[]
---------------------|-----------------------
15938 | { 2, 3, 4 }
15942 | { 1, 2 }
How can I change the original SQL query to give me the result above?
You want to use array_agg, this should work:
SELECT i_adgroup_id, array_agg(i_category_id)
FROM adgroupcategories_br
WHERE i_adgroup_id IN
(
SELECT i_adgroup_id
FROM adgroupusers_br
WHERE i_user_id = 103713
)
GROUP BY i_adgroup_id;
Note that i_category_id is no longer in the GROUP BY as it is now being aggregated.