I've searched on my question but I couldn't really find what I was looking for or maybe I just didn't understand the examples. If there is a similar post please point me to the right thread.
What I'm trying to do is the following: I have results like the table below which I generated with a very simple query:
SELECT id, first_name, last_name, email, roles, created
FROM user
As you can see a user can have two roles: User or teacher. Some persons are only teacher and some are only user. However, some of them are both teacher and user.
Now I want to group by e-mail adres, but of course this doesn't work on persons who are both user and teacher.
I would like to group by e-mail and in case a person has both roles I want to keep the user role in the results. I understood this can be done with an if condition but I can't figure out where or how to do it.
+------+------------+-----------+-----------------------+--------------+
| id | first_name | last_name | email | roles |
+------+------------+-----------+-----------------------+--------------+
| 9798 | person | one | personOne#gmail.com | ROLE_USER |
| 9800 | person | one | personOne#gmail.com | ROLE_TEACHER |
| 9801 | person | two | personTwo#gmail.com | ROLE_TEACHER |
| 9802 | person | three | personThree#gmail.com | ROLE_TEACHER |
| 9803 | person | four | personFour#gmail.com | ROLE_USER |
+------+------------+-----------+-----------------------+--------------+
So my query should be something like this:
SELECT id, first_name, last_name, email, roles, created
FROM user
group by email (if count(email) > 1 "ROLE_USER from roles should end up in results")
Could anybody point me in the right direction or make an example? Thanks so much!
If there are only 2 roles you could
select * from t where roles = 'role_user'
union
select * from t where roles = 'role_teacher' and
((select count(*) from t t1 where t1.email = t.email) = 1)
order by id;
+------+------------+-----------+-----------------------+--------------+
| id | first_name | last_name | email | roles |
+------+------------+-----------+-----------------------+--------------+
| 9798 | person | one | personOne#gmail.com | ROLE_USER |
| 9801 | person | two | personTwo#gmail.com | ROLE_TEACHER |
| 9802 | person | three | personThree#gmail.com | ROLE_TEACHER |
| 9803 | person | four | personFour#gmail.com | ROLE_USER |
+------+------------+-----------+-----------------------+--------------+
4 rows in set (0.03 sec)
But this won't work if there are roles that are duplicated for an email.
it is probably easier than you think, but like you said, being new, might not have understood. That said, and trying to interpret other commands not to your data scenario is a little harder. You know you have the post possible combinations of 3... User, Teacher or both. I would just add a column to represent each possible grouped by email. Now, being that you are grouping by email, do you still need the "ID", and "created" fields? I'm not sure, but we'll throw those in too just in case.
select
u.email
max( u.first_name ) first_name,
max( u.last_name ) last_name,
max( case when u.roles = 'ROLE_USER' then 1 else 0 end ) IsUserRole,
max( case when u.roles = 'ROLE_TEACHER' then 1 else 0 end ) IsTeacherRole
from
user u
group by
u.email
By applying a max, it for the name, if you had a person whose name changed, or had a mis-entry into the system, you would just get one, but if names were the same, it does not matter. As for the User / Teacher roles, I am just returning a 1 if the record returns true, otherwise a zero. This SHOULD get you what you need.
if i understand the question right something like this should help you
SELECT u.id,u.email, u.fname, u.llname, group_concat(r.role) FROM user u
LEFT OUTER JOIN user r ON (u.email = r.email) GROUP BY u.email
Related
Good morning. I'm trying to pull the username of the user from the column in to_id. Is there. It'd be simple if I was just filtering on to_id, but I also need records from another column from_id. I've attempted doing a UNION to get around this issue, but it only pulls records from user.id 3 of course.
Does anyone happen to know a way around this? I'm somewhat new to writing complex SQL queries. Haven't been able to figure much out from similar questions.
SELECT
users.username, -- Placeholder until username from to_id can be pulled
payment.id,
to_id,
amount,
state,
type,
timedate
FROM
payment
LEFT JOIN users ON users.id = payment.to_id AND users.id = payment.from_id
WHERE to_id = 3 OR from_id = 3
The result of that would be along the lines of:
+----------+----+-------+--------+----------+------+---------------------+
| username | id | to_id | amount | state | type | timedate |
+----------+----+-------+--------+----------+------+---------------------+
| NULL | 1 | 1 | 12.56 | COMPLETE | u2u | 2021-11-12 06:09:21 |
| NULL | 2 | 1 | 43.00 | COMPLETE | u2u | 2021-11-12 06:17:10 |
| NULL | 3 | 3 | 2.25 | COMPLETE | u2u | 2021-11-12 06:22:53 |
+----------+----+-------+--------+----------+------+---------------------+
Username is null due to the two Joins being AND. If it's OR, the username will show up, but the rows will be there twice. Once with the to_id username, once with the from_id username.
So you have one users table for all payers and payees accounts and one transaction table with two ID columns (payer and payee)? You need to join the users table to the transaction table twice, once to get the payer info, once to get the payee info.
select
payment.from_id,
from_user.username,
payment.to_id,
to_user.username,
payment.id,
amount,
state,
type,
timedate
from payment
left join users as from_user
on from_user.id = payment.from_id
left join users as to_user
on to_user.id = payment.to_id
where payment.to_id = 3 OR payment.from_id = 3
So I have a table called the Activities table that contains a schema of user_id, activity
There is a row for each user, activity combo.
Here is a what it might look like (empty rows added to make things easier to look at, please ignore):
| user_id | activity |
|---------|-----------|
| 1 | swimming | -- We want to match this
| 1 | running | -- person's activities
| | |
| 2 | swimming |
| 2 | running |
| 2 | rowing |
| | |
| 3 | swimming |
| | |
| 4 | skydiving |
| 4 | running |
| 4 | swimming |
I would like to basically find all other users with at least the same activities as a given input id so that I could recommend users with similar activities.
so in the table above, if I wanna find recommended users for user_id=1, the query would return user_id=2 and user_id=4 because they engage in both swimming, running (and more), but not user_id=3 because they only engage in swimming
So a result with a single column of:
| user_id |
|---------|
| 2 |
| 4 |
is what I would ideally be looking for
As far as what I've tried, I am kinda stuck at how to get a solid set of user_id=1's activities to match against. Basically I'm looking for something along the lines of:
SELECT user_id from Activities
GROUP BY user_id
HAVING input_user_activities in user_x_activities
where user1_activities is just a set of our input user's activities. I can create that set using a WITH input_user_activities AS (...) in the beginning, what I'm stuck at is the user_x_activities part
Any thoughts?
To get users with the same activities, you can use a self join. Let me assume that the rows are unique:
select a.user_id
from activities a1 join
activities a
on a1.activity = a.activity and
a1.user_id = #user_id
group by a.user_id
having count(*) = (select count(*) from activities a1 where a1.user_id = #user_id);
The having clause answers your question -- of getting users that have the same activities as a given user.
You can easily get all users ordered by similarity using a JOIN (that finds all common rows) and a GROUP BY (to summarize the similarity per user_id) and finally an ORDER BY to return the most similar users first.
SELECT b.user_id, COUNT(*) similarity
FROM activities a
JOIN activities b
ON a.activity = b.activity
WHERE a.user_id = 1 AND b.user_id != 1
GROUP BY b.user_id
ORDER BY COUNT(*) DESC
An SQLfiddle to test with.
In MySql database I have a fairly common users and groups with a pivot users_groups to allow N:M relationships.
table users
id | name
--------+----------
1 | Joe
2 | Anna
3 | Max
Table groups
id | name
---------+----------
1 | Red
2 | Blue
3 | Green
Table users_groups
id | userid | groupid
---------+--------+---------
1 | 1 | 2
2 | 3 | 2
3 | 1 | 3
3 | 2 | 1
So... Member of the Red(1) group is Anna(2), member of the Green(3) group is Joe(1) and members of the Blue(2) group are Joe(1) and Max(3).
When a user is logged in, I have the user id (e.g. 1 for Joe) and I would like to lookup all the other users in a specific group that my logged in user is also a member of. How can I get the list of users in that group?
I need to lookup the group name using text supplied from a form and the userid will be obtained from the auth/login code. If the user is not part of the group, they should not be able to get a list of the group members.
For Red group, I should only see one user (Anna) when logged in as Anna
User | Group | Users in Group must include the current user
------+------------
1 | Red | EMPTY
User | Group | Users in Group must include the current user
------+------------
2 | Red | Anna
User | Group | Users in Group must include the current user
------+------------
3 | Red | EMPTY
And for Blue group, if I am logged in as Joe or Max then I should see a list of users (Joe and Max)
User | Group | Users in Group must include the current user
------+------------
1 | Blue | Joe, Max
User | Group | Users in Group must include the current user
------+------------
2 | Blue | EMPTY
User | Group | Users in Group must include the current user
------+------------
3 | Blue | Joe, Max
For Green group, I should only see one user (Joe) when logged in as Joe
User | Group | Users in Group must include the current user
------+------------
1 | Green | Joe
User | Group | Users in Group must include the current user
------+------------
2 | Green | EMPTY
User | Group | Users in Group must include the current user
------+------------
3 | Green | EMPTY
=== UPDATE #1 ===
Using #Erico's answer and the fiddle below with updated table schema to include enabled and email fields, I can do the following with additional enabled column checks. However, I'd like to return all the Users as individual rows in the results set rather than a single Users column with all data in there.
http://sqlfiddle.com/#!9/80da98/2
SELECT '1' as User, name as Group,
(SELECT GROUP_CONCAT(email) FROM users u, users_groups ug
WHERE u.enabled = 1 AND u.id = ug.user_id AND ug.group_id = g.id AND ug.group_id
IN (SELECT group_id FROM users_groups WHERE user_id = 1)
) as Users
FROM groups g
WHERE g.name = 'Blue' AND g.enabled = 1
=== UPDATE #2 ===
Instead of returning the results in a single row:
User | Group | Users in Group must include the current user
------+------------
1 | Blue | Joe, Max
or using emails instead of names
User | Group | Users in Group must include the current user
------+------------
1 | Blue | joe#mycompany.com, max#hiscompany.com
I'd like to return the users full information in a row per user, thus searching as user Joe(1) in Group Blue(2) would return:
User | Name | Email
------+------------
1 | Joe | joe#mycompany.com
3 | Max | max#hiscompany.com
Here is an example with sub-queries that displays the results as shown in your question.
Joe showinng group Blue:
SELECT '1' as `User`, name as `Group`,
(SELECT GROUP_CONCAT(name) FROM users u, users_groups ug
WHERE u.id = ug.user_id AND ug.group_id = g.id
AND ug.group_id IN (SELECT group_id FROM users_groups WHERE user_id = 1)
) as `Users`
FROM groups g
WHERE g.name = 'Blue'
http://sqlfiddle.com/#!9/1a735/22/0
So I have two tables, one containing user info (Users), and the other containing info of which users not to show (Settings). So, I want to do a query that will show all the users in the users table except the ones listed in the settings. Thanks in advance.
Users
| id | name |
===============
| 1 | adam |
| 2 | alex |
| 3 | andrew|
Settings
| id | name | value | user_id |
===============================
| 1 | hide | 1 | 1 |
I want the results to be :
| id | name |
==============
| 1 | alex |
| 2 | andrew|
Something like:
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM settings WHERE name="hide");
would get only the users from the users table which are not in the settings table where the setting name equals "hide"
To get list of something present in one table, but not in another (related) one, you can either use the famouse LEFT JOIN-NULL combo:
SELECT u.id, u.name
FROM users AS u
LEFT JOIN settings AS s
ON s.user_id = u.id
WHERE s.user_id IS NULL
... or NOT IN clause on dependent sub-query:
SELECT u.id, u.name
FROM users AS u
WHERE u.id NOT IN (SELECT user_id FROM settings)
I usually use the first one, but according to this article, there should not be any significant speed difference between those. Anyway, I'd suggest benchmarking them on your specific DB instance, then choosing the best one.
SELECT * FROM users WHERE id NOT IN (SELECT * FROM settings)
try this
SELECT * FROM users WHERE id NOT IN (SELECT user_id FROM settings WHERE user_id='1');
I did take a look in and outside of SO and still don't know if this can be done. I have a table that looks like this:
User ID | Role | First Name | Last Name | Email |<br>
0001 | K | John | Smith | e#e.co|<br>
0002 | Q | Jane | Dickens | q#q.co|<br>
0003 | K | John | Smith | e#e.co|<br>
0004 | J | Jack | Paper | j#j.co|<br>
As you can see, the table contains a duplicate due to a user entering their information two separate times. I want to display the rows that
1. have the same first name
2. have the same last name
3. have the same email
4. do NOT have the same User ID
I can get the first three conditions to work with an inner join subquery, but I get 0 returned results when ever I try to to add in the fourth condition.
Thanks in advance for your help!
SELECT GROUP_CONCAT(`User ID`) as IDs, Role, `First Name`, `Last Name`, Email
FROM users_table
GROUP BY Role,`First Name`,`Last Name`,Email
Will give a table like
IDs | Role | First Name | Last Name | Email |
0001,0003 | K | John | Smith | e#e.co|
0002 | Q | Jane | Dickens | q#q.co|
0004 | J | Jack | Paper | j#j.co|
The trick is to GROUP BY everything except ID.
You could also do:
SELECT COUNT(`User ID`) as numIDs, GROUP_CONCAT(`User ID`) as IDs,
Role, `First Name`, `Last Name`, Email
FROM users_table
GROUP BY Role,`First Name`,`Last Name`,Email
HAVING numIDs > 1
to get
numIDs |IDs | Role | First Name | Last Name | Email |
2 |0001,0003 | K | John | Smith | e#e.co|
Anyhow, you get the point of how to vary it to your purposes.
Try something like:
select *
from tb_users
where (first_name, last_name, email) in
(select first_name, last_name, email
from tb_users
group by first_name, last_name, email
having count(*) > 1)
I am assuming that your table does not contain true duplicate rows (where the User ID also matches). I think it should be as simple as this to get the relevant rows back (with my adjusted column and table naming scheme):
SELECT ui.user_id, ui.role, ui.first_name, ui.last_name, ui.email
FROM user_info AS ui
INNER JOIN user_info AS udi
ON ui.first_name = udi.first_name
AND ui.last_name = udi.last_name
AND ui.email = udi.email
AND ui.user_id != udi.user_id;
I would use count(*) and group by clause.
Like this
SELECT count(*) as count FROM table group by concat(firstname,'\n',last_name) having count=1;
I think you want to delete duplicate rows. Only take count by group by and delete duplicate rows.
select * from tb_users
group by first_name, last_name, email
having count(*) > 1
You don't have to download extensions; go left bottom corner, click settings, click Keyboard Shortcuts, and search "duplication". You should see as in the below image and assign the key combination you want. I choose shift+D because I don't want to lose the current behavior of ctrl+D it is also very beneficial.