SQL query where record does not exist - sql

Having trouble coming up with a sql query to identify records where a user is missing providers that should be listed in the userproviders table.
Providers
ProviderID
ProviderName
User
UserId
UserName
UserProviders
UserID
ProviderID
I'm trying to identify users that do not have any ProviderID assigned in the UserProvider table or do not have a specific provider listed in the userproviders table.
select *
from users u
left join UserProviders up on u.UserId = up.ClientId
where up.ProviderId is null
This gets me records where the user doesn't have any provider assigned, but its possible that the user could have a provider but is missing some other needed provider.
Thanks for any help!
For example
There are 3 providers in the provider table
Providers
1, A
2, B
3, C
User
1,Bill
2,Ted
User 1 has 2 records in UserProviders
Userproviders
1,1
1,2
2,1
2,3
So in this example I want to be able to determine that Bill doesn't have a record in Userproviders for provider 3 and that Ted doesn't have a record for provider 2.

If I understand correctly, It appears you can Use "IN" Like so:
select *
from users u
left join UserProviders up on u.UserId = up.ClientId
where up.ProviderId NOT IN ( select providerId from UserProviders Where UserId != u.UserId )

If you want all missing user/provider combinations, then use a cross join to get all combinations of users and providers. Then remove the ones that exist:
select u.userid, p.providerid
from users u cross join
providers p left join
userproviders up
on up.userid = u.userid and up.providerid = p.providerid
where up.userid is null;
If you just want users that have no provider at all, use not exists;
select u.*
from users u
where not exists (select 1
from userproviders up
where up.userid = u.userid
);
If you want users who don't have a specific provider, then use not exists:
select u.*
from users u
where not exists (select 1
from userproviders up
where up.userid = u.userid and up.providerid = ?
);

Related

select a column from another table mulipletimes problem

User
USER_ID USERNAME
1 -
2 Chris
3 Dave
4 Vlad
Issue
Creator RESOLVER VERIFIER
2 3 4
2 3 1
3 1 1
expected output:
Creator RESOLVER VERIFIER
Chris Dave Vlad
Chris Dave -
Dave - -
current code I have:
SELECT creatorid.username, resolverid.username, verifierid.username
FROM issue
JOIN user creatorid ON issue.creator = creatorid.user_id
JOIN user resolverid ON issue.resolver = resolverid.user_id
JOIN user verifierid ON issue.verifier = verifierid.user_id
do i have to join the table 3 times to get the corresponding username of the user_id in issue table or is there is a simpler way of doing this? Asking as this is a simplified version of the tables, the User and Issue table contains a lot of other columns. Thanks
Because of the join, you will see each issue three times which is not what you want. You could use three scalar subqueries to get around that:
select i.id,
(select username from users u1 where u1.user_id = i.creator) as creator,
(select username from users u2 where u2.user_id = i.resolver) as resolver,
(select username from users u3 where u3.user_id = i.verifier) as verifier
from issue i;
This isn't going to be fast though.
Another option is to aggregate all user_id / username pairs into a JSON object, then use that in a sub-query:
select i.id, -- other columns from the issue table
u.names ->> i.creator::text as creator,
u.names ->> i.resolver::text as resolver,
u.names ->> i.verifier::text as verifier
from issue i
join lateral (
select jsonb_object_agg(user_id, username) as names
from users u
where u.user_id in (i.creator, i.resolver, i.verifier)
) u on true;
The traditional way to do this is:
select i.*, uc.username, ur.username, uv.username
from issue i left join
users uc
on uc.user_id = i.creator left join
users ur
on ur.user_id = i.resolver left join
users uv
on uv.user_id = i.verifier;

Select users that have n roles for reporting functions SQL

I have an application that uses a standard Role, User and UserRoleJoin architecture.
The application needs to send reports to users based on what group of roles they may be in. For example
Role:
ID Name
1 Lead
2 Mech
3 Elec
4 Auditor
5 Assigner
UserRole:
UserID RoleID
1 1
1 2
1 4
2 1
2 4
I want to be able to send one report to all users that are Leads, Mech and Auditors or a different report to all users that are leads and auditors.
The first report would only be sent to user 1 while the second report would be sent to user 2
Should I have a different table that handle roles to reports associations or should I deal with these groups by a select query?
There are several ways. I would be inclined to use group by and having:
select ur.UserId
from UserRole ur join
Role r
on ur.RoleID = r.Id
where name in ('Leads', 'Mech', 'Auditors')
group by ur.UserId
having count(*) = 3;
The advantage of this approach is that the logic is all in the having clause. You can make it more flexible, such as all Leads and Mechs who are not Auditors.
If those groups are stable enough they deserve a way to persist them in the DB, kind of Group(ID PK, Name), RoleGroup(GroupID , RoleID)
declare #grpName varchar(50) = 'my_group';
select ur.UserId
from UserRole ur
join RoleGroup rg on rg.RoleID = ur.RoleID
join Group g on rg.GroupID = g.ID and g.Name = #grpName
group by ur.UserId
having count(*) = (select count(*) n
from RoleGroup rg
join Group g on rg.GroupId = g.ID and g.Name = #grpName);

How to do a JOIN in Oracle SQL?

I have two tables Users and User_Org.
Users ( user_id,first name,last name, active_ind, email)
User_Org (user_id, org_id)
I have to write a Oracle SQL query, where it should return all users whose active_ind is 1 and org_id of associated user in User_org match the given org_id.
I have tried below, it is not working
select *
from Users u
join User_ORG org
where org.ORGANIZATION_ID = 12345
and Active_ind != 0;
You are missing the on clause of the join. Other than that, if you want users with an active_ind of 1, I'd state that directly with an equality check (=) instead of dancing around it with an inequality check.
SELECT u.*
FROM users u
JOIN user_org org ON u.user_id = org.user_id
WHERE org.org_id = 12345 AND active_ind = 1

Select statement using primary key with no primary key

Ok so I have a table for notes in my database and a table for users in my database. Lets say notes table looks like this:
NoteId NoteTitle NoteAuth
--------------------------------
1 TempTitle 254
2 TempTitle2 871
and Users table looks like:
UserId UserName
-------------------
254 Bob
871 Jim
How can I select from the Note table but select the NoteAuth as the UserName from the Users table. Basically how can I use a primary key without a primary key being set up on the table.
SELECT NoteID, NoteTitle, UserName
FROM Notes INNER JOIN Users ON Notes.NoteAuth = Users.UserID
There's no requirement for any keys to exist to use a column in a JOIN.
You can try something like this
SELECT Notes.NoteId, Notes.NoteTitle, Notes.NoteAuth
FROM Notes
INNER JOIN Users ON Notes.NoteAuth = Users.UserId
WHERE Users.UserName = 'Bob'
Edit
Here is a version that returns the user name for a specified note author.
SELECT Users.UserName, Notes.NoteId, Notes.NoteTitle, Notes.NoteAuth
FROM Notes
INNER JOIN Users ON Notes.NoteAuth = Users.UserId
WHERE Notes.NoteAuth = 254
select n.NoteId, n.NoteTitle, n.NoteAuth, u.UserName
from Notes n
inner join User u on n.NoteAuth = u.UserID
The lack of a primary key will cause lack of table integrity. Now you won't be able to create a foreign key between the tables. This means that going forward you will be allowed to create a note with a user that doesn't exist in the Users table.
This won't stop you from
SELECT n.NoteTitle, u.UserName
FROM NoteTable n LEFT JOIN Users u ON n.NoteAuth = u.UserId
That will work in SqlServer.
The problem is is if you have a note that has a NoteAuth that doesn't exist in the users table, you'll end up with a NULL username. Use an ISNULL to replace NULL with something like 'No Username'.
But like I said, there won't be any integrity between the tables.
SELECT U.Username, N.NoteTitle from Notes N, Users U WHERE N.NoteAuth = U.UserId

MySQL- complex data query in a single statement

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.