MySQL- complex data query in a single statement - sql

Consider the following structure :
alt text http://aeon-dev.org/pap/pap_db.png
Ignore the table user_token.
Now, imagine that you need to get all the roles related to an user, wich may be through it's related groups or directly related to him. In case the same role appears related to a group and the user directly, the role related to the user will prevail over the role given by the group.
Is there any chance this could be done in a single query?
Cheers!

Use:
SELECT DISTINCT r.name AS role_name
FROM USER u
LEFT JOIN USER_HAS_ROLE uhr ON uhr.user_id = u.id
LEFT JOIN USER_HAS_GROUP uhg ON uhg.user_id = u.id
LEFT JOIN GROUP_HAS_ROLE ghr ON ghr.group_id = uhg.group_id
LEFT JOIN ROLE r ON r.id = uhr.role_id
OR r.id = ghr.role_id
WHERE u.username = ?

try this:
Select role_id
From user_has_role
Where userId = #UserId
Union
Select role_id
From user_has_group g
Join Group_has_Role gr
On gr.GroupId = g.GroupId
Where userId = #UserId

This query will get every role a single user has either directly or given by a group
SELECT * FROM ROLE WHERE ID IN (
SELECT ROLE_ID
FROM USER_HAS_ROLE
WHERE USER_ID = 1
UNION
SELECT ROLE_ID
FROM USER_HAS_GROUP UG
INNER JOIN GROUP_HAS_ROLE GR ON UG.GROUP_ID = GR.GROUP_ID
WHERE USER_ID = 1
)

You could find all distinct roles for user 1 like:
select distinct role_id
from (
select uhr.user_id
, uhr.role_id
from user_has_role uhr
union all
select uhg.user_id
, ghr.role_id
from user_has_group uhg
join group_has_role ghr
on ghr.group_id = uhg.group_id
where not exists
(
select *
from user_has_role uhr
where uhr.user_id = uhg.user_id
and uhr.role_id = ghr.role_id
)
) user2role
where user_id = 1
Not sure how a role related to a user should "prevail", but you can assign priorities to them in the union.

Related

How to select users that exist in one group and only that group - oracle

I am trying to get a list of users that only exist in a single group and no other groups. The users can be in multiple groups.
The group I want to get users in has an ID of 20064212 and belongs to the acc_id 200640
There are three tables involved:
Users
USER_PK_ID,
ACC_ID,
Active,
Deleted
USER_GROUP_USER
GROUP_ID, USER_PK_ID
USER_GROUP
ID,
ACC_ID,
DESCRIPTION,
ACTIVE
I can get all the users in the group with the fallowing query but it does not exclude users that exist in other groups also.
SELECT DISTINCT (U.USER_PK_ID)
FROM USER_GROUP_USER U
JOIN USERS US ON US.USER_PK_ID = U.USER_PK_ID
WHERE GROUP_ID = 20064212
AND US.acc_id = 200640
AND US.DELETED = 'N'
I have tried various queries but they always seem to return users that also exist in other groups
SELECT DISTINCT (U.USER_PK_ID)
FROM USER_GROUP_USER U
JOIN USERS US ON US.USER_PK_ID = U.USER_PK_ID
WHERE GROUP_ID = 20064212
AND US.acc_id = 200640
AND US.DELETED = 'N'
AND GROUP_ID NOT IN (
SELECT ID
FROM USER_GROUP
WHERE acc_id = 200640
AND ID != 20064212)
Hoping I parsed your text correctly; this SQL returns users with ACC_ID= 200640 and DELETE='N' and that are member of group with ID 20064212, but not member of any other group.
select u.user_pk_id
from users u
join user_group_user ugu on (u.user_pk_id = ugu.user_pk_id)
join user_group ug on ugu.group_id=ug.id
where ugu.group_id=20064212
and u.acc_id=200640
and u.deleted='N'
and not exists (
select null
from user_group_user ugu2
where ugu2.group_id != ugu.group_id
and ugu.user_pk_id = ugu2.user_pk_id
);

SQL Oracle - Multiple count queries on multiple tables

Maybe for some people it might look very simple, but I just cant get it.
My tables are:
CREATE TABLE USERS (user_ID number PRIMARY KEY, username varchar2(32), password varchar2(32));
CREATE TABLE VIDEOS (video_ID number PRIMARY KEY, title varchar(64), description varchar(128));
CREATE TABLE VIEWS (view_ID number PRIMARY KEY, user_ID number, video_ID number);
CREATE TABLE FAVORITES (fav_ID number PRIMARY KEY, user_ID number, video_ID number);
I ve created those separated queries:
SELECT u.username AS "Username", count(*) AS "Views"
FROM Views v, Videos vd, Users u
WHERE v.user_id = u.user_id
AND v.video_id = vd.video_id
GROUP BY u.username
SELECT u.username AS "Username", count(*) AS "Favorites"
FROM Favorites f, Videos vd, Users u
WHERE f.user_id = u.user_id
AND f.video_id = vd.video_id
GROUP BY u.username
And I want a query to show something like that in only one simple query:
Username Views Favorites
-------------------------------
Person1 12 1
Person2 234 21
...
I Googled bunch of similar questions but I couldnt make any of them to work.
So any help is greatly appreciated.
You are progressing on the right track. -> You got two queries and you wish to see them together. You could perform a full outer join to get your results you are looking for as below.
with fave
as (
SELECT u.username AS "Username"
, count(*) AS "Favorites"
FROM Favorites f
JOIN Videos vd
ON f.video_id = vd.video_id
JOIN Users u
ON f.user_id = u.user_id
GROUP BY u.username
)
,views
as (SELECT u.username AS "Username"
, count(*) AS "Views"
FROM Views v
JOIN Videos vd
ON v.video_id = vd.video_id
JOIN Users u
ON v.user_id = u.user_id
GROUP BY u.username
)
select isnull(f.username,v.username) as username
,f.favourites
,v.views
from fave f
full outer join views v
on f.username=v.username
Since you know your data better, you could optimize the query further. Eg: it could be a rule that user who has set a favourite would also have viewed the video. If this is true then you can write a better query to optimize the dataset in a single block, instead of two blocks using full outer join
Aggregate separately in Views:
select user_id, count(*) counter
from Views
group by user_id
and Favorites
select user_id, count(*) counter
from Favorites
group by user_id
and finally LEFT join Users to the above queries:
select u.username,
coalesce(v.counter, 0) Views,
coalesce(f.counter, 0) Favorites
from users u
left join (
select user_id, count(*) counter
from Views
group by user_id
) v on v.user_id = u.user_id
left join (
select user_id, count(*) counter
from Favorites
group by user_id
) f on f.user_id = u.user_id
I used LEFT joins because there may exist users that did not see any video or do not have any favorites. In any of these cases COALESCE() will return 0 instead of null.
The table Videos is not needed.

H2 making one select from 2

I got 3 tables, Users, courses and course realation tables. I want to get users who aren't on specific course. So I figure I need somehow merge 2 selects with right join. How could I make one select from 2 selects?
SELECT ID, NAME, LASTNAME, ROLE FROM COURSERELATION JOIN USERS ON
ID_USER = ID WHERE ID_COURSE = ?
RIGTH JOIN
SELECT ID, NAME, LASTNAME, ROLE from COURSERELATION JOIN USERS ON
ID_USER = ID WHERE ID_COURSE != ?
You need to extract users for which it doesn't exist a record of that user for the specific course. You can filter the rows using a NOT EXISTS clause over a subquery.
Please try below query:
SELECT u.ID,
u.NAME,
u.LASTNAME,
u.ROLE
FROM USERS u
WHERE NOT EXISTS (SELECT 1
FROM COURSERELATION s
WHERE s.id_user = u.id
AND s.id_course = 'YOUR_COURSE_ID_HERE' )

Query that joins two table where match exists and removes result if ID exists in another table

This query gets the the ID, First Name, Date of Birth by joining two tables together where a mutual match exists
Example of mutual match:
Amy likes Mary
Mary likes Amy
SELECT u.ID, u.firstname, u.dob, i.[Image]
FROM [dbo].[User] AS u
INNER JOIN [dbo].[Images] AS i ON u.ID = i.Id
WHERE u.ID IN (
SELECT userB FROM [dbo].[LikesRefined]
WHERE userA = #ID OR userB = #ID
UNION
SELECT userB FROM [dbo].[LikesRefined]
WHERE userA = #ID OR userB = #ID
);
I want to filter this result by using except clause on another table but I keep getting this error
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
except
(select paidA
from [dbo].[Matches]
WHERE paidA = #ID
AND (userA = #ID or userB = #ID))
end
I'm still confused, but I think this may do the trick:
SELECT u.ID ,
u.firstname ,
u.dob ,
i.[Image]
FROM [dbo].[User] AS u
INNER JOIN [dbo].[Images] AS i ON u.ID = i.Id
INNER JOIN dbo.[LikesRefined] lr ON (u.ID = lr.userA OR u.ID = lr.userB)
LEFT OUTER JOIN dbo.Matches m ON u.ID = m.paidA
AND ( m.userA = u.ID OR m.userb = u.ID )
WHERE (lr.userA = #ID OR lr.userB = #ID)
AND m.paidA IS NULL
We get rid of the union operator and just check for the ID in either userA or userB in the LikeRefined table. Then we left join to dbo.Matches and just look for records where there is no match.
When using union operator all select statements must have the same number of columns

Join 2 tables based on a single table

I can't seem to get the join / query that I need!
Lets say I have 3 tables (trimmed for this post...)
user_courses
(int) user_id
(int) course_id
users
(int) user_id
(txt) name
(txt) access
courses
(int) course_id
(txt) course_desc
What I am trying to do is select select all users with a certain access type that are taking a specific course (course_id)
something like...
SELECT *
FROM user_courses uc
JOIN users u
ON uc.user_id = u.user_id
JOIN courses c
ON uc.course_id = c.course_id
WHERE u.access = "foobar"
... but working like I want it to :)
I can get close, but will have extra users that don't have the correct access type.
Use inner join.
SELECT *
FROM user_courses uc
INNER JOIN users u
ON uc.user_id = u.user_id
LEFT JOIN courses c
ON uc.course_id = c.course_id
WHERE u.access = "foobar"
perhaps:
select * from users u
where u.access='foobar'
and exists (select 1 from user_courses uc where uc.user_id=u.user_id)
Cheers
Try
...
WHERE ISNULL(u.access, '') = 'foobar'
Not sure if your 'access' field can be null?