I have what appears to be a simple query, but is alluding my boolean challenged mind (not enough java (the liquid kind) today).
Three tables:
Users = (UserID, Username, Enabled, LoggedIn, SessionID, Email, SettingsTableVersion, FullName, Initials, UserData, InitialStatusID)
Groups = (GroupID, Groupname, Description, AutoAdd)
GroupMembers = (GroupID, UserID, ProjectID, IsMember)
I have a bunch of users and a dozen or so groups. I have a World group that has every User in it. I have a Terminated Users Group that has just 4 users in it.
What I want is a query that looks at World (everyone is in it) and takes out the Terminated User group users names. This yields me all active users! Blimey if this isn't causing me to pull my hair out. I would surmise its essentially World minus the intersection of World and Terminated Users. No luck thus far. SQL Server 2012.
TIA
A nested query?
Select *
from users
where userid not in ( select userid
from groupmembers
where groupid=[terminated])
Or is that too slow?
If I can assume
The groupnames are 'world' and 'terminatedusers'
duplicates do not exist in group members (groupID and userID are a Unique index)
you really mean World is ALL users an a terminated user coudnl't exist w/o being in the world group.
.
SELECT U.userID
FROM USERS U
INNER JOIN GROUPMEMBERS GM
on U.UserID = GM.UserID
INNER JOIN GROUPS G
on G.GroupID = GM.GroupID
WHERE GroupName in ('World', 'TerminatedUsers')
GROUP BY U.UserID
HAVING count(GM.GroupID) = 1
This basically find all the groups each user is in for the two groups. then only return those who are in just 1 group.
You could join to two defined sets as well:
SELECT U.userID
FROM Users U
INNER JOIN GroupMembers GMWorld
on U.userID = GMWorld.userID
and GMWorld.GroupID = [ID for world]
LEFT JOIN GroupMembers GMTerminated
on U.userID = GMTerminated.UserID
and GMTerminated.GroupID = [ID for terminated]
WHERE GMTerminated.userID is null
If you don't want to use the ID's you could left join twice to Group for GMterminated and GMWorld to use the names.
The 2nd query basically joins users to a worldset and a terminated set we keep all users in world except those having a record in the terminated set.
This one did the trick! Issue was I had one user that was deleted (flips the Enabled bit) and then re-added so they appeared in the list until I added the Enabled = 1. Thanks xQbert... again! Awesome stuff.
SELECt fullname
FROM Users U
LEFT JOIN GroupMembers GMWorld
on U.userID = GMWorld.userID
and GMWorld.GroupID = 3
LEFT JOIN GroupMembers GMTerminated
on U.userID = GMTerminated.UserID
and GMTerminated.GroupID = 14
WHERE GMTerminated.userID is null and Enabled = 1
Related
-- 2. In one table, show how many private topics, admins, and standard users each organization has.
SELECT organizations.name, COUNT(topics.privacy) AS private_topic, COUNT(users.type) AS user_admin, COUNT(users.type) AS user_standard
FROM organizations
LEFT JOIN topics
ON organizations.id=topics.org_id
AND topics.privacy='private'
LEFT JOIN users
ON users.org_id=organizations.id
AND users.type='admin'
LEFT JOIN users
ON users.org_id=organizations.id
AND users.type='standard'
GROUP BY organizations.name
;
org_id is the foreign key that reals both the users table and topics table. It keeps giving me the wrong result by only either counting the number of admins or standard users and putting that for all rows in the each column. Any help is really appreciated as I have been stuck on this for a while now!
So, I am getting an error when I do as you said which is that the users table cannot be specified more than once. I updated the code to how you said to write it but still nothing. They really don't give me any sample data either but I just made some queries and saw the number of times there are private topics for example, which is in the privacy column of the topics table. When I dont get this error as I said, the joins seem to overwrite themselves where each row for all the columns is the same as the last join.
It appears to me that topics and users have no relationship. You're just trying to get the result together in a single query. There are other and possibly better ways to accomplish that but I think this will fix what you've got already (assuming you have id columns for each table.)
SELECT
organizations.name,
COUNT(DISTINCT topics.id) AS private_topic,
COUNT(DISTINCT users.id) FILTER (WHERE users.type = 'admin') AS user_admin,
COUNT(DISTINCT users.id) FILTER (WHERE users.type = 'standard') AS user_standard`
FROM organizations
LEFT JOIN topics
ON organizations.id = topics.org_id AND topics.privacy = 'private'
LEFT JOIN users
ON users.org_id = organizations.id
GROUP BY organizations.name;
I propose this as a more straightforward way:
SELECT
min(o.name) as "name",
(
select count(*) from topics t
where t.org_id = o.id AND t.privacy = 'private'
) as private_topics,
(
select count(*) from users u
where u.org_id = o.id and u.type = 'admin'
) AS user_admin,
(
select count(*) from users u
where u.org_id = o.id and u.type = 'standard'
) AS user_standard
FROM organizations o
GROUP BY o.id;
We have two tables.
Table 1 - Users: Contains the users
Table 2 - Restrictions: User that can only access certain room. If a user is not in this table they can access all the rooms.
Now I need a query where I pass the room and it returns the users that have access. For example, I pass RoomId = 70 and my expected result is 1, 3.
1 because it actually has access to only room 70 and 3 because since it's not in the restriction table it has access to all rooms.
The problem is with an inner join I lose number 3, and with left join I keep number 2. So I cannot figure out how to relate the tables. Is there any way to do it directly with joins?
You can try with UNION
SELECT usr.UserID FROM Users usr
JOIN Restrictions res ON usr.UserID = res.UserID
WHERE res.RoomID = #myParameter --we take the users permitted for given room
UNION
SELECT UserID
FROM Users
WHERE UserID NOT IN (
SELECT DISTINCT UserID
FROM Restriction
) --plus the users that have permission in all rooms
I think, this should work. You don't really need a join to solve the issue.
select
userid
from
users u
where
userid is not in (
select
userid
from
restrictions
where
userid = u.userid
and roomid = #roomId
)
I strongly advise you not to use not in with a subquery. It is just a dangerous habit. If the subquery returns any NULL values, then the outer query returns no rows.
So, I would recommend:
select userid
from users u
where exists (select 1
from restrictions r
where r.userid = u.userid and
r.roomid = 70
) or
not exists (select 1
from restrictions r
where r.userid = u.userid
);
I would also strongly advise you to change your data model. If someone has access to one room and that row is deleted from restrictions, then they will have access to all rooms. That seems dangerous. You should explicitly list all rooms useres have access to.
I've got 3 tables that look vaguely like this:
Users
----------
UserID
Name
Phone
User Groups
-----------
GroupID
Activity
Group Membership
---------------
UserID
GroupID
Independent Actives
-------------------
UserID
Activity
The idea is that a user can perform an activity either as part of a group or on their own. What I want to do is return all the people that partake in a certain activity. What I have been able to write so far lets me return all the users which are in groups that undertake that activity. What I want to add to this is the ability to see the people that do the activity independently. This is what I have so far:
SELECT
users.name, users.phone, user_groups.activity
FROM users
INNER JOIN group_membership ON group_membership.userID = users.userID
INNER JOIN user_groups ON user_groups.groupID = group_membership.groupID
WHERE user_groups.activity = 'Knitting';
The above bit works fine and it shows all of the users that are part of groups that do knitting, but I also want it to show all the users that are knitting independently. This is what I have attempted to add:
SELECT
users.name, users.phone, user_groups.activity
FROM users
INNER JOIN group_membership ON group_membership.userID = users.userID
INNER JOIN user_groups ON user_groups.groupID = group_membership.groupID
INNER JOIN independent_activity ON independent_activity.userID = users.userID
WHERE user_groups.activity = 'Knitting' OR independent_activity.activity = 'Knitting';
The problem here is the syntax, I understand the algorithm that I'm trying to do but I don't know how to transfer it into sql and so any help is appreciated.
You could use a UNION in this case
SELECT users.NAME
,users.phone
,user_groups.activity
FROM users
INNER JOIN group_membership ON group_membership.userID = users.userID
INNER JOIN user_groups ON user_groups.groupID = group_membership.groupID
WHERE user_groups.activity = 'Knitting'
UNION
SELECT users.NAME
,users.phone
,independent_activity.activity
FROM users
INNER JOIN independent_activity ON independent_activity.userID = users.userID
WHERE independent_activity.activity = 'Knitting';
You also might want to lookup the differences between a UNION and a UNION ALL and decide the one that suites your requirement.
You've got a working answer from SoulTrain. However, for completeness sake I'd like to mention that you don't have to join all those tables. (You could use outer joins here and remove duplicate matches with DISTINCT, but that's not necessary. You don't have to query the users table twice either. And you don't need UNION for doing the distinct job.)
Simply select from the one table you want to display data from, i.e. the users table, and then use EXISTS or IN to get only those users that are either in one set or another.
select name, phone
from users
where userid in
(
select userid
from independent_actives
where activity = 'Knitting'
)
or userid
(
select userid
from group_membership
where groupid in (select groupid from user_groups where activity = 'Knitting')
)
my hosting company doesn't allow me to save query/view in mysql database (don't ask me ..why! i don't know), so i've to build an all in one nested query (that is difficult for my sql skills).
My app is a simple "ticket managment system"
Here the table structure ticket_master
ticket_id
assignedto_user
...
The other table, for users
userid
username
I've to get the count of ticket per user, starting from the USERS table to include ALL users (either who haven't ticket opened).
The result must be
userid, username, tot_ticket
1, mr a, 3
2, mr b, Null (or zero)
3, mr c, 2
4, mr d, Null (or zero)
...
Thanks in advance!
Select U.userid, U.username
, Count(TM.ticket_id) As tot_ticket
From users As U
Left Join ticket_master As TM
On U.userid = TM.assignedto_user
Group By U.userid, U.username
SELECT
userid,
username,
COUNT(ticket_id)
FROM users
LEFT OUTER JOIN ticket_master on users.userid = ticket_master.assignedto_user
Not much different than #Thomas answer, except that I would avoid the grouping if your user list is already unique.
Let's say we have these tables;
table user:
- id
- username
- email
table user2group:
- userid
- groupid
table group:
- id
- groupname
How do I make one query that returns all users, and the groups they belong to (as an array in the resultset or something..)
select u.id, u.username, u.email, g.groupid, g.groupname
from user u
join user2group ug on u.userid=ug.userid
join group g on g.groupid=ug.groupid
order by u.userid
As you are looping through the result set, each time you see a new userid make a new user object (or whatever) and add the groups to it.
Eric's answer is great, but I would use a LEFT JOIN instead of an INNER to get users that do not belong to any group as well.
SELECT
u.id,
u.username,
u.email,
g.groupid,
g.groupname
FROM
user u
LEFT JOIN user2group ug ON u.userid = ug.userid
LEFT JOIN group g ON g.groupid = ug.groupid
ORDER BY
u.userid
Both of the above are more or less correct (deepends if each user has a group or not). But they will also both give a result set with several entries for each user.
There are ways of concatenating every group member into one comma separated string, I'd suggest you read about it here:
http://www.simple-talk.com/sql/t-sql-programming/concatenating-row-values-in-transact-sql/
Another method I personally like is to use bit values instead of the relational table user2group
table user then gets a int (or bigint) field group, and each group ID is assigned one bit value (ie: 1,2,4,8,16 and so on) The value of the user table's group field is then the sum of the groupID it's assigned to. To query if its got a group you do:
where (group AND groupID = groupID)