MDX Exclude results where a value exists in a hierarchy - ssas

Please excuse me if I get some of the terminology wrong, I am relatively new to MDX/OLAP.
I have a dimension for determining ethical walls. The dimension looks like this:
Ethical Wall (dimension)
--> Matter ID (hierarchy)
--> Walled (hierarchy)
--> White Listed Initials (hierarchy)
--> Black Listed Initials (hierarchy)
The [Walled] hierarchy contains either true or false, depending on if the matter has a wall applied.
The White and Black list hierarchies contain user initials of people who either have or do not have access to a matter, respectively. Note, matters are either white listed or black listed, it is never a combination of the two.
I have been able to account for the no wall scenario and white list scenario relatively easily, but am having lots of issues with the black list scenario. This is the where clause I have come up with so far:
({
(
[Ethical Wall].[Walled].&[True]
,[Ethical Wall].[White Listed Initials].&[XXX]
,[Ethical Wall].[Black Listed Initials].&[]
)
,(
[Ethical Wall].[Walled].&[True]
,[Ethical Wall].[White Listed Initials].&[]
,-{[Ethical Wall].[Black Listed Initials].&[XXX]}
)
,(
[Ethical Wall].[Walled].&[False]
,[Ethical Wall].[White Listed Initials].&[]
,[Ethical Wall].[Black Listed Initials].&[]
)
})
Stripping down and representing it in a table the initial dataset, from which I am filtering down, looks something like this:
I want to select only the Ids to which the user with initials XXX has access. Applying the filter from above I get back all 3 Ids. The result set I am looking for is only Id 1 and 2. The filer from above matches like this:
I understand why my filter is retrieving all 3 Ids, but I don't understand how to revise the middle portion of the filter to exclude Ids properly. This is the offending portion of the filter:
,(
[Ethical Wall].[Walled].&[True]
,[Ethical Wall].[White Listed Initials].&[]
,-{[Ethical Wall].[Black Listed Initials].&[XXX]}
)
How can I revise my filter to match on that data set like this?

Why can't you simplify to this?
WHERE
({
(
[Ethical Wall].[Walled].&[True]
,[Ethical Wall].[White Listed Initials].&[XXX]
)
,(
[Ethical Wall].[Walled].&[False]
,[Ethical Wall].[White Listed Initials].&[]
)
});

We have found the solution!!
Utilizing sets:
SET notwalled AS exists(
selectedmatters,
{
[Ethical Wall].[Walled].&[False]
}
)
SET whitelisted AS exists(
selectedmatters,
{
[Ethical Wall].[White Listed Initials].&[XXX]
}
)
SET blacklisted AS EXCEPT(
selectedmatters,
exists(
selectedmatters,
{
[Ethical Wall].[Black Listed Initials].&[XXX],
[Ethical Wall].[Black Listed Initials].&[]
}
)
)
And then union:
UNION(notwalled, whitelisted, blacklisted)
No more crying for me.

Related

SQL - Returning combinations of ID from tables if combination not found in another

I have four tables of interest: users, models, questions and labels.
"Labels" contains rows that describes a user's answer to a question on a model. e.g username TEXT, mid INT, qid INT, answer TEXT
I am interested in finding out what model-question pairs the user is still required to provide. A user is asked to provide an answer for every combination of model and questions that appear in their respective tables. So for a given username, I can have rows of model ids and question ids.
Users:
Bacon, XXXX, XXXX, XXXX, ...
Mark, XXXX, XXXX, XXXX, ...
Models:
1, climateOne, XXXX, ....
2, climateTwo, XXXX, ....
3, climateTwo, XXXX, ....
Questions:
1, "Is this a question?"
2, "And another?"
labels:
Bacon, 1, 2, "Yes is was..."
Bacon, 3, 2, "Another what?!"
So the result of asking "what model question pairs has 'Bacon' not completed" would be the return of:
(1,1)(2,1)(2,2)(3,1)
To get all possible combinations of models and questions, use a cross join:
SELECT models.id,
questions.id
FROM models
CROSS JOIN questions
Then filter out those that have been completed:
...
WHERE (models.id, questions.id) NOT IN (SELECT mid, qid
FROM labels);
Thanks go to CL. for the point in the right direction. This code worked for me as I was using python's sqlite3 package. I have included the username specification too. However, I have no clue whether it is efficient or not :)
SELECT m.mid, q.qid
FROM models m CROSS JOIN questions q
WHERE NOT EXISTS(
SELECT 1
FROM labels l
WHERE l.username = ? AND l.mid = m.mid AND l.qid = q.qid
)
Thanks all!

Where on hasmany in sequelize with count

I am not the best at UML/database diagrams but the following hopefully shows my DB design (MsSQL)
I have a "Location" table with zero to many pallets assiociated with it (there are 0-many pallets IN a location). However that location can be one of two types, location x or y. This diagram simplifies it, but there are many different types of location, and very different fields for each type.
I am using Sequelize as an ORM, and trying to figure out how to do a particular query. I think I am close but quite stuck.
What I need is:
Select a single LocationTypeX where "active" is true, and where its corresponding Location has less than 10 pallets in it.
Previously I have gone and got all LocationTypeX where "active" is true. Included Location and Pallet (on location) and did it all in code to figure out which location is relavent. however that is taking forever, as there are thousands of Locations and loads of pallets spread out through them.
All I am after is to show the Location Name. That is it. But the Location name of one that matches the above condition. Hopefully someone can help?
So far I have
models.Location.findAll({
group: ['Location.id', 'Pallets.id'],
attributes: ['Location.id', 'Pallets.id', [models.sequelize.fn('COUNT',models.sequelize.col('Pallets.id')), 'PalletCount']],
include: [{
model: models.Pallet,
attributes: []
}]
}).then((ret)=> {
console.log(ret);
});
But this doesn't do the "active" check. And also doesn't do the where clause on the amount of pallets. Back to square one
I have managed to answer my own question with raw SQL that I can use in Sequelize. However I would still be interested to know how to do it in Sequelize
models.sequelize.query(
`SELECT TOP 1 Locations.id, Locations.name FROM LocationTypeX
INNER JOIN Locations ON LocationTypeX.LocationId = Locations.id
LEFT JOIN Pallets on (Locations.id = Pallets.LocationId)
WHERE LocationTypeX.active = 1
GROUP BY Locations.id, Locations.name
HAVING COUNT(Pallets.id) < 3`
, { type: models.sequelize.QueryTypes.SELECT})

Group by query, each group has to not have any item not in a List

In need a query that will help me solve this.
Here's my table 'tags':
id (int)
name (String)
user_id (int)
hardware_id (int)
I am grouping the results of the 'tags' table by hardware_id. I also have a List of tags (List<string>).
I want to get the hardware Id of the groups that all of the tags in the custom List matches at a name in the table above.
In other words, I want to get the hardware_id's that the custom List tags matches their name's. There might be name's that doesn't have a match in the custom list, but all of the custom list tags, must be in the group, and if it satisfies this need, I can the Id of that group.
I found it hard to explain and I didn't get an answer for that. I thought about doing it with foreach because it was so hard to solve, but I couldn't do it either and it's very inefficient to do it that way.
Example:
List : ['tag1', 'tag2']
Table Rows:
1, tag1, 5, 1
2, tag2, 5, 1
3, tag3, 5, 1
4, tag4, 5, 2
5, tag5, 6, 2
In this case, I should get the hardware_id of 1, because although one of the hardware Id's have tag3, it doesn't have any rows with a tag name that isn't in the List. IF the List had 'tag4', the hardware_id = 1 WOULDN'T be returned, because the List has a tag that the hardware_id group doesn't have.
If the Group doesn't have an item that the List has, it won't appear in the final result.
Someone game me this code, but it didn't work:
List<decimal> matchingHardareIds = db.tags.GroupBy(x => x.hardware_id)
.Where(x => x.All(s => tags.Contains(s.name.ToLower()) || 0 == tags.Count() && (s.user_id == userId)))
.Select(x => x.Key).ToList();
In that query, when I have one tag in the List and in the table I have several items with hardware_id 1 and one of them has a 'name' that is equal to the value in the List it will return empty results. this is because the rows in the table for a specific group by hardware_id, has a row with a name that doesn't appear in the custom List.
I need a query in either Entity Framework or Linq. Thanks a lot.
Use this:
var t = db.tags.GroupBy(x => x.hardware_Id)
.Where(x => tags.All(y =>
x.Any(z=> z.name == y)))
.Select(x=>x.Key).ToList();
Can not provide you with the entity framework or linq query, but the sql solution is to count the matches like this:
SELECT hardware_id
FROM tags
WHERE name IN (<list>)
GROUP BY hardware_id
HAVING COUNT(DISTINCT name) = <listDistinctCount>
<listDistinctCount> is the count of distinct values in the list. Which you can prepare prior to the query.

SQL join both ways to one result

I have two tables "TestItem" and "Connector" where Connector is used for relating two items in "TestItem".
I have two questions in prioritized order. But first, feel free to suggest alternative approaches. I'm open for suggestion to completely rethink my approach to what I want to achieve here.
Question 1) How to get relations both ways returned in the same result
Question 2) How to filter the most efficient way for specific items
Q1)
Two tables
Table: "TestItem"
ID, ITEM
1, "John Doe"
2, "Peggy Sue"
3, "Papa Sue"
Table: "Connector"
MOTHER, CHILD
1,2
The connector table will be used for several purposes (see below), but this is a destilled scenario for the equal type connection, like for instance marriage. If "John Doe" is married to "Peggy Sue" that information should also be sufficient to return "Peggy Sue" as married to "John Doe".
I can do this in two queries, but for efficiency (especially regarding my question 2) I'd appreciate this done in one query, so an implementation is not dependent on which way the connection is defined.
What is the most efficient way to do this?
Two queries approach to illustrate how the data can be fetched, but how one connection is missed one way or the other.
//Connector through "mother"-part SELECT ITEM, SUBITEM FROM TestItem
INNER JOIN (
SELECT MOTHER, ITEM AS SUBITEM
FROM Connector
INNER JOIN TestItem ON Connector.CHILD = TestItem.ID
) AS SUB ON TestItem.ID = SUB.MOTHER
/* WHERE ITEM = "John Doe" return "Peggy Sue" => Correct
WHERE ITEM = "Peggy Sue" return nothing => Wrong
*/
//Connector through "child"-part SELECT ITEM, SUBITEM FROM TestItem
INNER JOIN (
SELECT CHILD, ITEM AS SUBITEM
FROM Connector
INNER JOIN TestItem ON Connector.MOTHER= TestItem.ID
) AS SUB ON TestItem.ID = SUB.CHILD
/* WHERE ITEM = "John Doe" return nothing => Wrong
WHERE ITEM = "Peggy Sue" return "John Doe" => Correct
*/
Q2) Having the two approaches returned in one result may increase the amount of data involved, and hence bring down performance. If my focus is Peggy Sue, I assume sorting out only the relevant data as early as possible will improve performance. Is there a neat way of doing this from top level, or will every sub-query require an added WHERE?
PS: Some more information of the bigger perspective.
I'm planning to use the connector table for several purposes, both of the mentioned equal type, like colleagues, family, friends, etc, but also for hierarchical connection types like mother/child, leader/employee, country/city.
Thus solutions eliminating the mother/child-type connection may not suit my bigger purpose.
Basically I'm requesting how to handle the equal type of connections without losing the opportunity to use the same architecture and data for hierarchical connections.
Peggy Sue may through the same dataset be defined as daughter of Papa Sue through the relation
Mother, Child, Mother_type, Child_type
3, 2, Father, Daughter
1, 2, Married to, Married to
(But this is as mentioned on the side of what I'm requesting here. )
UNION ALL might be what you are looking for:
select mother.id as connectedToId,
mother.item as connectedToItem,
'Mother' as role
from TestItem ti
join Connector c on c.child = ti.id
join TestItem mother on c.mother = mother.id
where ti.item = 'John Doe'
union all
select child.id as connectedToId,
child.item as connectedToItem,
'Child' as role
from TestItem ti
join Connector c on c.mother = ti.id
join TestItem child on c.child = child.id
where ti.item = 'John Doe'

Combine results from two tables into one recordset

I have two tables items and content.
items:|ID|menu|img
table
itemcontent |ID|parent|title|content
content holds is paired to items by parent holding the title and content
i want to search all the items and also print out those records wich do not have a title present in the itemcontent table
whereby the titles will be printed as "Empty".
so printing out the output would look something like:
title: test1 and ID: items.ID=1
title: Empty and ID: items.ID=2
title: Empty and ID: items.ID=3
title: test2 and ID: items.ID=4
title: Empty and ID: items.ID=5
etc...
I tried the following and then some but to no avail:
SELECT items.*, itemcontent.title, itemcontent.content
FROM items, itemcontent
WHERE itemcontent.title LIKE '%$search%'
AND itemcontent.parent = items.ID
order by title ASC
A little help would be much appreciated
Since you want all the rows from items whether or not they have a match in itemcontent, plus a field from itemcontent when there is a match you need to use an OUTER JOIN:
SELECT items.*, COALESCE(itemcontent.title, 'empty'), itemcontent.content
FROM items LEFT OUTER JOIN itemcontent ON itemcontent.parent = items.ID
WHERE (itemcontent.title LIKE '%$search%' OR itemcontent.title IS NULL)
ORDER BY items.ID, itemcontent.title ASC
There are small differences among SQL dialects (for instance, not all versions have COALESCE) so if you want a more precise answer indicate which product you're using.
Just to be sure you might want to ORDER BY itemcontent.title and not just title or select itemcontent.title AS title? Do you have a field called title in the items table?