A double outer join - sql

I have a table People, a table Permission and a table Action. Permission is there to provide a many-to-many relationship between People and Action.
My goal is simple : I want to look for one person in People, I want to see the permission listed in Permission, AND every action available, wether the person has the permission or not.
Note that a member of People is not necessary represented in Permission. So, "John" is only allowed to do something if he's got the permission written in the database.
Ideally, the result would look something like :
+-------------------------------------------+
+ People.name | Action.name |Allowed |
+-------------------------------------------+
| John Doe | Launching missiles | N |
| John Doe | Deleting code | Y |
+-------------------------------------------+
Before I get to there, I'm simply tring to build a simple query with every data.
Getting the list of permission of someone, even if he is not present in the permission table is easy :
SELECT * FROM people pp LEFT OUTER JOIN permission pr ON pp.id = pr.people_id
WHERE pp.name = 'John';
Getting the list of permission and actions is easy :
SELECT * FROM permission pr LEFT OUTER JOIN action a ON pr.action_id = a.id
However, I can't seem to perform a double outer join that would get me everything I want :
SELECT * FROM people pp LEFT OUTER JOIN permission pr ON pp.id = pr.permission_id
LEFT OUTER JOIN people WHERE pp.name = 'John'
Shows John, the fact that he's got no permission... but no actions whatsoever.
In other words, results look something like :
+-----------------------------------------+
+ Name | People_id | Action_id |Action |
+-----------------------------------------+
| John | | | |
+-----------------------------------------+
When I wanted :
+-----------------------------------------------------------+
+ Name | People_id | Action_id |Action |
+-----------------------------------------------------------+
| John | | | Launching missiles |
| John | | | Deleting codes |
| John | | | (every other actions) |
+-----------------------------------------------------------+
So, is what I want possible ? If so, how can I achieve it ? (I'm using PostgreSQL).
edit: Here is a sqlfiddle : http://sqlfiddle.com/#!2/6d502

SELECT pp.name, pr.id_people, pr.id_action, a.name as action_name
FROM people pp
CROSS JOIN action a
LEFT JOIN permission pr
ON pr.id_people = pp.id
AND pr.id_action = a.id
SQLFiddle: http://sqlfiddle.com/#!15/5a7b1/4
To filter by person name add to query:
WHERE pp.name = 'John'

This should work.
SELECT
P.name as "people.name",
IFNULL(pm.id_people,''),
IFNULL(pm.id_action,''),
A.name as "action.name"
FROM Action A
CROSS JOIN People P
LEFT JOIN permission pm
ON pm.id_action = a.id
AND pm.id_people = p.id
WHERE p.name = 'John'

Related

How to filter query by related privileges

I am trying to write select that filters users by containing at least one permission with display = 1. My tables looks like the following:
User:
-id
-user_email_id
UserGroupRelation:
-id
-user_id
-user_email_id
-user_group_id
UserGroupPermission
-id
-permission_id
-display(bool)
-user_group_id
One user, can have multiple groups and permissions that are assigned to group. I would like to select all users that are in groups with at least one permission that have display set to 1. How would I do it?
That is what I tried and it didn't work.
SELECT *
FROM User as u
LEFT OUTER JOIN
UserGroupRelation as ugr on ugr.user_id = u.id and ugr.user_email_id = u.user_email_id
LEFT OUTER JOIN
UserGroupPermission as ugp on ugp.user_group_id = ugr.user_group_id
WHERE
ugp.display = 1
I think the problem is that User has multiple group relations and groups have multiple permissions. Maybe should I use another select in FROM clause?
Sample data:
User:
{id=1, user_email_id=1},
{id=2, user_email_id=2}
UserGroupRelation:
{id-1, user_group_id=1, user_id=1, user_email_id=1},
{id=2, usergroup_id=2, user_id=2, user_email_id=2}
UsergroupPermission:
{id=1, permission_id=1, display=1, user_group_id=1},
{id=2, permission_id=1, display=0, user_group_id=2}
Result should return only user that has id=1 because he is connected to group_id = 1 which has permission with display=1, user with id 2 is not in result because he has permission that has display= 0. It is simple example because user can have multiple groups and group can have multiple permissions but only one that h as display = 1 is required to be in the result
I believe your SELECT is simply badly formatted. Try running the following in place of what you have shared above:
SELECT * FROM #User AS u
INNER JOIN UserGroupRelation AS ugr
ON ugr.[user_id] = u.id AND ugr.user_email_id = u.user_email_id
LEFT OUTER JOIN UserGroupPermission AS ugp
ON ugp.user_group_id = ugr.user_group_id
WHERE
ugp.display = 1;
If I run this in my test environment against your sample data, I recevie the following resultset:
+----+---------------+----+---------+---------------+---------------+----+---------------+---------+---------------+
| id | user_email_id | id | user_id | user_email_id | user_group_id | id | permission_id | display | user_group_id |
+----+---------------+----+---------+---------------+---------------+----+---------------+---------+---------------+
| 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
+----+---------------+----+---------+---------------+---------------+----+---------------+---------+---------------+
On a side note, I would change LEFT OUTER JOIN UserGroupPermission AS ugp to INNER JOIN UserGroupPermission AS ugp given that "display" is required in your expected resultset.

SQL Query to get mapping of all users to their logins

What's a query that I can use to get a list of all logins associated with each user in SQL Azure?
So far I've found the following two queries to get all users and all logins, but I haven't found any way to see which user goes with which login:
SELECT * from sys.sql_logins -- get all logins
SELECT * from sys.sysusers -- get all users
In case you find it helpful, here's the documentation for the structures of those the tables:
sys.sql_logins:
https://msdn.microsoft.com/en-us/library/ms174355.aspx?f=255&MSPPError=-2147217396
Column names: name, principal_id, sid, type, type_desc, is_disabled, create_date, modify_date, default_database_name, default_language_name, credential_id, is_policy_checked, is_expiration_checked, password_hash
sys.sysusers: https://msdn.microsoft.com/en-us/library/ms179871.aspx
Column names: uid, status, name, sid, roles, createdate, updatedate, altuid, password, gid, environ, hasdbaccess, islogin, isntname, isntgroup, isntuser, issqluser, isaliased, issqlrole, isapprole
It's hard to tell you your correct answer b/c we don't know the structure of your tables. If you share that we can help more. But below should get you to where you need to go.
They way to do it is by a MySQL JOIN. In this case you should use a INNER or OUTER JOIN depending on how your database is structured.
If you have 2 tables that are structured below you can do an FULL OUTER JOIN
[sys.sql_logins]
| sid| userID | name |
| 1 | 1 | ssmith |
| 2 | 2 | bbob |
[sys.sysusers]
| sid| name |
| 1 | Sam Smith |
| 2 | Billy Bob |
You can use the following query to do it
SELECT A.name as userName, B.name as login
FROM sys.sysusers A
FULL OUTER JOIN sys.sql_logins B
ON A.sid = B.sid
This will result in :
| userName | logins |
| Same Smith | ssmith |
| Billy Bob | bbob |
Here is a link to more types of MySQL Joins
https://www.sitepoint.com/understanding-sql-joins-mysql-database/
http://dev.mysql.com/doc/refman/5.7/en/join.html
http://www.w3schools.com/sql/sql_join.asp
I think you can join on the sid, try this (but maybe just select whatever columns you want):
select l.*, u.*
from sys.sql_logins l
join sys.sysusers u on l.sid = u.sid

combine 2 sql's from different tables into one query

I have for example as first query: (ararnr = article number)
Select ararnr,ararir,aoarom from ar left join ao ON AR.ARARNR=AO.AOARNR WHERE AR.ARARKD=1389
the second query uses the result from the first column from the first query to search in another table
Select votgan, sum(ststan) as totalStock from vo INNER JOIN st on vo.voarnr=st.starnr where voarnr = ararnr
How could I combine both ?
Please note : Not all articlenumbers from the first query will be found in the second, but I need them in my result.
In the result I need the columns from both queries.
EDIT
for example :
first query returns article numbers and the description:
+---------+--------------+
| ararnr | aoarom |
+---------+--------------+
| a123456 | description1 |
| b123456 | description2 |
| 0123456 | description3 |
+---------+--------------+
second query returns the totalstock for those articles:
+---------+--------------+
| ararnr | totalstock |
+---------+--------------+
| a123456 | 12 |
| b123456 | |
| 0123456 | 6 |
+---------+--------------+
Note the second one doesn't return a value since the articlenumber doesn't exist in this table.
In my result I would like to get the articlenumber with corresponding description and stock.
+---------+--------------+-----------+---------+
| ararnr | aoarom | totalStock| vovoan |
+---------+--------------+-----------+---------+
| a123456 | description1 | 12 | 2 |
| b123456 | description2 | | 1 |
| 0123456 | description3 | 6 | |
+---------+--------------+-----------+---------+
I'm using sql on db2
SECOND EDIT
The first query will select some article numbers (ararnr) from table ar and find the corresponding description (aoarom) in another table ao.
The second query finds the stock (vovoan and sum ststan) from two differend tables vo and st for the article numbers found in the first query.
The result should have the article number with corresponding description with corresponding stock from vo and st
I can't fully understand what you're asking, but another join may assist you.
example:
SELECT ar.ararnr, ar.ararir, ar.ararom, vo.votgan, SUM(vo.ststan) as totalStock
FROM ar LEFT JOIN ao ON [id=id] LEFT JOIN vo ON [id=id]
Because I can't tell what your tables structure are, or what you're really asking for, this is the best response I can give you.
This also may be what you're looking for:
Combining 2 SQL queries and getting result set in one
You can use this query.
SELECT ar.ararnr, ar.ararir, ar.ararom, vo.votgan, SUM(vo.ststan) as totalStock
FROM ar
LEFT JOIN ao ON ao.ararnr = ar.ararnr
LEFT JOIN vo ON vo.voarnr = ao.ararnr
If you are using SQL Server as database then this can be done with help of OUTER APPLY
SELECT ararnr,aoarom ,temp.totalStock
FROM ar
LEFT JOIN ao ON AR.ARARNR=AO.AOARNR
OUTER APPLY(
SELECT sum(ststan) as totalStock
FROM vo
INNER JOIN st on vo.voarnr=st.starnr
where voarnr = ar.ararnr
)temp
WHERE AR.ARARKD=1389
You'd get a much more complete answer if you were to post the table structure and desired result, but..
You can use the first query as a resultset for your second query, and join to it. something like:
Select
votgan,
sum(ststan) as totalStock
from vo
inner join (Select
ararnr,
ararir,
ararom
from ar
left join ao .....) z on vo.voarnr = z.ararnr
EDIT:
Select
votgan,
sum(ststan) as totalStock,
z.ararnr,
z.aoarom
from vo
inner join (Select
ararnr,
ararir,
ararom
from ar
left join ao .....) z on vo.voarnr = z.ararnr

SQL: find the earliest occurrence of a row in a table based of values from multiple tables

I realize this question has been asked many times and I am have looked through many posts concerning this issue for over a day now. Unfortunately I've been unable to resolve my specific issue and would greatly appreciate any help that you all can offer.
I believe this is a variation of the "greatest-n-per-group" problem that comes up on StackOverflow several times per week.
The query is being run against a database for work tickets. The data I need is spread out across many table and I am consolidating it into a single area to work with. In this specific instance, the update table contains multiple rows for a specific work ticket. I am trying to join it to the ticket table and only grab the earliest update-date for that ticket where the user id matches the user associated with the ticket from the user table. Basically I'm using when the user_id is changed to determine when a ticket is being assigned to a particular user.
UPDATE_TABLE
updateNumber | user_id | date | ticket_number
11 | 4586b03 | 2011-11-30 | 923479283
12 | 6786t03 | 2011-11-30 | 923479283
13 | 7986003 | 2011-12-02 | 923479283
14 | 7986003 | 2011-12-03 | 923479283
15 | 7986003 | 2011-12-04 | 923479283
16 | 5838397 | 2011-10-02 | 391983247
17 | 7986004 | 2012-01-03 | 663738223
18 | 7986003 | 2011-08-04 | 391983247
Query:
select
min(TA.updated_at) as UpdateVal
from Tickets T
inner join Users U on U.id = T.assigned_user_id
inner join UserGroup AU on U.login = AU.[User]
inner join TicketUpdate TA on TA.task_id = T.id
where
TA.task_id = 923479283 and TA.user_id = 7986003
returns: 2011-12-02
This approach works when I hard code the task_id and user_id for a specific row like above. However when I substitute the T.id for 923479283 and U.id for 7986003 to get this info for all the tickets the query returns nothing. I've tried many different solutions including joining the TicketUpdate table on itself via alias and so on.
Please HELP!
You need to add those columns on your SELECT and GROUP BY:
select TA.task_id, TA.user_id, min(TA.updated_at) as UpdateVal
from Tickets T
inner join Users U on U.id = T.assigned_user_id
inner join UserGroup AU on U.login = AU.[User]
inner join TicketUpdate TA on TA.task_id = T.id
GROUP BY TA.task_id, TA.user_id

How should joins used in mysql?

If i have two tables like
user table-"u"
userid | name
1 | lenova
2 | acer
3 | hp
pass table-"p"
userid | password
1 | len123
2 | acer123
3 | hp123
as for as i learnt from tutorials I can join these 2 tables using many joins available in
mysql as said here
If i have a table like
role table-"r"
roleid | rname
1 | admin
2 | user
3 | dataanalyst
token table-"t"
tokenid| tname
1 | xxxx
2 | yyyy
3 | zzzz
tole_token_association table-"a"
roleid | tokenid
1 | 1
1 | 2
3 | 1
3 | 3
3 | 1
I have to make a join such that I have to display a table which corresponds
like this "rolename" has all these tokens.How to make this? I am confused. Is it possible to make a join? I am liking mysql a lot. I wish to play with queries such that not playing. I want to get well versed. Any Suggestions Please?
It's easiest to see when the column names that need to be joined are named identically:
SELECT r.rname,
t.tname
FROM ROLE r
JOIN ROLE_TOKEN_ASSOCIATION rta ON rta.roleid = r.roleid
JOIN TOKEN t ON t.tokenid = rta.tokenid
This will return only the roles with tokens associated. If you have a role that doesn't have a token associated, you need to use an OUTER join, like this:
SELECT r.rname,
t.tname
FROM ROLE r
LEFT JOIN ROLE_TOKEN_ASSOCIATION rta ON rta.roleid = r.roleid
JOIN TOKEN t ON t.tokenid = rta.tokenid
This link might help -- it's a visual representation of JOINs.