Select rows from one table where mapping exists in another table - sql

My question revolves around using an Oracle Database to manage a mapping between Raw Entitlements to Business Friendly Roles.
Basically, I have two tables:
Mapping Table - this would contain what entitlements are required to fit into a particular applicationrole. Note that you must have ALL of the entitlements for a particular applicationrole to have it. Also, this could change on any day, so queries need to be dynamic in the sense that it could be 3 entitlements = a role or 10 entitlements = a role.
Application ApplicationRole Resource Action
--------------------------------------------------------
Test1 Admin appserver1 admin
Test1 Admin appserver2 admin
Test1 Admin appserver3 admin
test2 ReadOnly appserver1 ro
test2 ReadOnly appserver2 ro
Accounts Table - this table would contain raw data from servers, like what accounts exist on what servers:
Account Resource Action Application
-------------------------------------------------
abc123 appserver1 admin Test1
abc123 appserver2 admin Test1
abc123 appserver3 admin Test1
test2 ReadOnly appserver1 ro
What I am aiming for is to find what applicationroles (business friendly grouping) are applicable to my accounts. In this example, account abc123 has 3 entitlements, for appservers 1, 2 and 3, and has the admin entitlement. Looking at the mapping table, I can now say this account has applicationrole "admin". However, account test2 only has ro on a single server, and the mapping says it needs ro on two servers to have the role "ReadOnly", therefore, account test2 does NOT have the role.
The output from a query on this same data should look like:
Account Application ApplicationRole
----------------------------------------------
abc123 Test1 Admin
Later on, I'll also want a query that returns the opposite;all accounts that DON'T fit into a role. E.g.
Account Application Resource Action
----------------------------------------------
test2 test2 ReadOnly appserver1
Let me know if I can provide any more info! I can't really find what I am after online, seems pretty hard to search for.
Thanks guys! :)
EDIT:
I've managed to write up this query and it seems to work for the first part; not sure if it's the best way though, and any guidance would be great :)
SELECT *
FROM TEMP_USERDATA b
LEFT JOIN TEMP_MAPPINGTABLE a
ON a.application = b.application
AND a.oresource =b.oresource
AND a.action =b.action
WHERE (SELECT COUNT(c.application||c.oresource||c.action)
FROM temp_mappingtable c
WHERE c.application=a.application) =
(SELECT COUNT(DISTINCT application||oresource||action||account)
FROM temp_userdata
WHERE temp_userdata.application=a.application
);

Try this:
;WITH mapingdata AS ( SELECT application,
applicationrole,
resource,
action,
COUNT ( * ) AS rowcount
FROM temp_mappingtable
GROUP BY application,
applicationrole,
resource,
action),
WITH userdata AS ( SELECT account,
resource,
action,
application,
COUNT ( * ) AS rowcount
FROM user_data
GROUP BY account,
resource,
action,
application)
SELECT *
FROM mapingdata m, userdata u
WHERE m.application = u.application
AND m.resource = u.resource
AND m.action = u.action
AND m.rowcount = u.rowcount;

Related

one to one within a many to many relationship

I'd like to assign a primary role to a user with many roles and I'm wondering what method is preferable, if any. Either to make a primary_role_id column in the users table or add an is_primary column in the pivot table:
Users:
id
name
primary_role_id here?
1
alice
2
2
bob
1
Roles:
id
name
1
super
2
admin
Role User:
user_id
role_id
OR is_primary here?
1
1
true
1
2
false
2
1
false
2
2
true
Requirement
It is simple, but not quite that simple. What you really want is:
each User is permitted 1-to-n Roles
of that set, one RoleUser is primary
Therefore:
the IsPrimary indicator has to be in RoleUser
you need a CHECK Constraint on RoleUser, that calls a Function, to ensure that there is just 1 IsPrimary Role per User.
That is an ordinary capability in Standard SQL, available in genuine SQL Platforms, not possible in the freeware.
Requirement is Not
each User is permitted 1-to-n Roles
each User has 1 primary Role
which leads to maintenance complexity: the set is in one place, the indicator for the set in another. The Function required checks that the User has the Role in RoleUser that is declared as PrimaryRoleId.
which is inferior and incorrect
the "User has one-to-one PrimaryRole" is true as a result, but not as a declarative.

Access: Query specific users not in a profile

I have a table that displays user profile and users assigned.
Example
Profile User
-------- -----
ProfileA UserA
ProfileA UserB
ProfileA UserC
ProfileB UserA
ProfileB UserD
ProfileC UserB
ProfileD UserE
I am trying to create a query to verify that a group of specific users are not in the profile and display those profiles.
Example:
I want to display the profiles where UserA and UserC are not assigned to.
Output Example:
Profile
--------
ProfileC
ProfileD
I am trying to create this query in MS Access.
Presumably, you have a table of profiles. If so, use not exists:
select p.*
from profiles as p
where not exists (select 1
from user_profiles up
where up.profile = p.profile and up.user in ('UserA', 'UserC')
);
If you don't have a separate table -- which would seem odd to me -- you can do this with the profiles in your table. But in this case, conditional aggregation is a simple method:
select profile
from user_profiles
group by profile
having sum(iif(user in ('UserA', 'UserC'), 1, 0)) = 0;

Search single entity which is presented by multiple rows SQL

I have User table which contains same user represented by different entities all around. For example
User Table
==========================
id name
1 John Doe
2 Doe, John
3 Nicholas Cage
4 BlackRiderXXX
5 Nicholas cage
where users John Doe, Doe, John, BlackRiderXXX are the same people. Also, Nicholas Cage and Nicholas cage are the same people. Other tables refer to user.id randomly based on which user object did the action.
For Action table it'll look like
Action Table
==========================
id user_id some_other_stuff
1 1 ...
2 2 ...
3 1 ...
4 4 ...
5 3 ...
Where the actions 1,2,3,4 are all done by John Doe.
I'll have these users merged by the user manually meaning we'd know who is whom. They'd also select which User is the one they'd like to be as their main user account so we need to know this information as well.
I'm simplifiying a bit but I have a dozen tables which are like the Action table I provided above. We have mainly two use cases on how we will need to query:
1) Find actions which are done by user X (which should check all the users entities belonging to user X)
2) Find actions and group unique users
Main point is we will be using it everywhere around the codebase on 100+ queries so we want to design it well. How can I construct a system where the query will be simple enough also powerful enough to handle different querying ways?
Thanks
PS: We are using PostgreSQL
Why not include the "main" user in the first table?
User Table
id name main_user_id
1 John Doe 1
2 Doe, John 1
3 Nicholas Cage 2
4 BlackRiderXXX 1
5 Nicholas cage 2
Then you would join on:
select . . .
from actions a join
users u
on a.user_id = u.id
where u.main_user_id = 1;
If you want this selectable per end user, then use a different table:
create table end_user_users (
end_user_users_id serial primary key,
end_user_id int references end_users (end_user_id),
end_user_user_id int references users (id),
end_user_main_user_id int references users (id)
);
Then the query would look like:
select . . .
from actions a join
end_users_users euu
on euu.end_user_user_id = a.user_id and
euu.end_user_id = $my_id
where euu.end_user_main_user_id = 1;
You can use regexp_replace(),initcap() and trim() functions to refine and extract the common name strings to be grouped, and then generate values for newly created action_id column depending on them :
with new_action0 as
(
select u.id as id,
case when strpos(u.name,',') > 0 then
initcap(trim(regexp_replace(trim(u.name),'(.*),(.*)','\2 \1')))
else
case when lower(trim(u.name))='blackriderxxx' then
'John Doe'
else
trim(initcap(u.name))
end
end as name
from action u
)
select n.id, dense_rank() over (order by n.name) as user_id
from new_action0 n;
Demo
A new decent user table can be created by using this query with create table .. as statement

Query Parent and Children from single table

I currently have a single table that hosts all of my users. Now some users have team_leaders which reference the user id of the team leader which is also stored in the database.
Now, what I wanted to do do (and can't figure out) is how to query the database where it retrieves a list of the ids of all the team members and the leader in one result set.
For Example
name | id | team_leader
--------------------------------------------------
Jack | 1 | null
--------------------------------------------------
Susan| 2 | 1
--------------------------------------------------
Bob | 3 | 1
--------------------------------------------------
Eric | 4 | null
--------------------------------------------------
SELECT name FROM users where team_leader = '<some user's id>'
returns [ 'Susan', Bob']
But I would like it to return the team leader included, such as
['Jack', 'Susan', 'Bob']
Does anyone have any idea how to include the team leader in the query results?
EDIT:
Okay, so it seems like I have not explained myself 100%, my apologies. so the goal of this query is to do as follows.
I have another table called leads and there is a field there that is called user_id which correlates to the user that has access to the lead. Now, I want to introduce the ability for team leaders to update the leads that are associated with their accounts, so if the current user is a team leader they should have the ability to update the user_id from their id to anyone on their team, from one of their children to another, and from one of the children to themselves, but not to anyone not on their team. So the way I thought of it was to have a WHERE EXISTS or a WHERE IN (this would mean adding a field to the lead table called leader_id) and it checks if the new user_id is in a list of that team leader's members, including themselves.
Based off the example above.
UPDATE lead SET user_id = xxx
WHERE lead.id = yyy
AND ...
-- here is where I would check that the user_id xxx is part of the current
-- user's team which must be a team leader, for example user.id = 1
So my thought process was to get the previous query to then check against.
Hope this clears things up.
If I'm understanding correctly, you can just use or:
select name
from users
where team_leader = 1 or id = 1
WITH CTE AS(
SELECT name,id,team_leader FROM [users]
WHERE team_leader=1
UNION ALL
SELECT u.name,u.id,u.team_leader from [users] u
JOIN CTE ON CTE.empno=u.team_leader`enter code here`
and u.team_leader=1
)
SELECT * FROM CTE

Row-level security in Cloudera Impala

I need to implement row level security based on user id in Impala. The approach I am following right now is that I have a user to role mapping, and use that to form a master query as follows:
create view dervied_view as
select *, 1 as roleid from src_table where a = 1 and b = 2
union
select *, 2 as roleid from src_table where a = 1 and b = 3
...
...
And then, have another query as follows:
create view well_known_named_view as
select * from derived_view where roleid in
(select roleid from role_mapping table where userid = effective_user());
This way, whenever a user logs in, he just needs to query the well known view, without the need to create a view on a per user/role basis. The problem is that this query times out in Hue (which is where it will be used most often), and takes at least 10 minutes to execute a basic query on in the shell. Is there a better way to make this work?