MySQL - select mutual rows - mysql

I have a table like this:
user_id | wants_user_id | state
And I want to select rows which are mutual and have a state column with value "yes" or "maybe".
Example data:
Row 1: 1 | 2 | "yes"
Row 2: 2 | 1 | "maybe"
Row 3: 3 | 2 | "yes"
In this case I would like to select row 1 and 2 and on wants_user_id (second column) I would like to join user data from table users, but I can't figure out the sql command.
Thank you for your help.

Use a self-join to get matching rows (I'm assuming "mutual rows" here means users that want each other):
SELECT *
FROM myTable a
INNER JOIN myTable b ON a.user_id = b.wants_user_id
AND b.user_id = a.wants_user_id
INNER JOIN users ua ON a.user_id = ua.id
INNER JOIN users ub ON b.user_id = ub.id
WHERE a.state IN ('yes', 'maybe')
AND b.state IN ('yes', 'maybe')
In this case, you will get two "duplicate" rows, one for 1<->2 and one for 2<->1. To eliminate this, you can add a AND b.user_id > a.user_id to the join condition - this will select only one row of each pair.

Related

Select with Multiple Counts on Left Join on Same Table

I'm not certain that this can be done, I have a table of users with a related table of user activity joined on a foreign key. Activity has different types, e.g. comment, like etc. I need to get users filtered by the number of each different type of activity.
What I have so far is this:
SELECT
users.*,
COUNT(t1.id) AS comments,
COUNT(t2.id) AS likes
FROM users
LEFT JOIN activity AS t1 ON users.id = t1.user_id
LEFT JOIN activity AS t2 ON users.id = t2.user_id
WHERE t1.activity_type_id = 1 AND t2.activity_type_id = 2
GROUP BY users.id
HAVING comments >= 5 AND likes >= 5
This seems to be close but it's returning a user with a count of 5 both likes and comments, when in reality the user has 5 likes and 1 comment.
To be clear I want this query to return users who have 5 or more likes and also users who have 5 or more comments.
UPDATE:
I've created an SQL Fiddle. In this case I have 3 users:
User 1: 6 comments, 8 likes
User 2: 3 comments, 2 likes
User 3: 5 comments, 2 likes
I want the query to return only user 1 and 3, with their respective totals of likes and comments.
http://sqlfiddle.com/#!2/dcc63/4
You can use conditional summing to do the count and due to the way MySQL treats boolean expressions an expression like sum(case when et.name = 'comment' then 1 else 0 end) (the "normal" SQL syntax) can be reduced to sum(case when et.name = 'comment').
SELECT
u.id,
sum(et.name = 'comment') AS comments,
sum(et.name = 'like') AS likes
FROM users AS u
LEFT JOIN engagements AS e ON u.id = e.user_id
JOIN engagement_types AS et ON e.engagement_type_id = et.id
GROUP BY u.id
HAVING sum(et.name = 'comment') >= 5
OR sum(et.name = 'like') >= 5
Result:
| ID | COMMENTS | LIKES |
|----|----------|-------|
| 1 | 6 | 8 |
| 3 | 5 | 2 |
Sample SQL Fiddle

mysql retrieving unique id from table with division

In a table like this
ID | Category | Value
1 Device Computer
1 Location 1st Floor
2 Device Phone
2 Type Voip
2 Location 1st Floor
3 Device Computer
3 Location 2nd Floor
How do I get the ID of the where device='computer' and location='1st Floor'? The query is created programmatically and there might be many of these criteria that specifies a single ID in a statement.
You can use the join query like this for your problem.
select a.ID from MYTABLE a, MYTABLE b where a.ID=b.ID and a.Category='Device'
and a.VALUE='Computer' and b.Category='Location' and b.VALUE='1st Floor';
If there is may catogories like this then you must split the table like below.
TABLES :
Category with columns (CATOGORY_ID, CATOGORY)
Value with columns (VALUE_ID, VALUE)
MYTABLE with columns (ID, CATOGORY_ID, VALUE_ID)
then you should use join query.
select Distinct a.id
from myTable a inner join myTable b
on a.Id = b.Id
Where a.value = 'Computer' And b.value = '1st Floor' and a.Category = 'Device' and b.Category = 'Location'
Demo here

MySQL: Join based on multiple columns

I need to join table_1 and table_2 in MySQL and compare which user has the most winnings. Then update table_2.winner with the user id which has won..
table 1
city user winnings
1 a 99
1 b 0
1 c 50
1 d 2
table 2
city user_1 user_2 winner
1 a b a
1 c d 50
However I'm struggling to figure out how to join the tables thus far I have
SELECT table_1.winnings AS win_a, table_1.winnings AS win_b
FROM table_1, table_2
WHERE table_2.user_1 = table_1.user
AND table_2.user_2 = table_1.user
http://sqlfiddle.com/#!2/c855b/1
You can join against the table multiple times like this:
SELECT IF(user1.winnings > user2.winnings, "user1", "user2")
FROM table_2 games
JOIN table_1 user1 ON games.user_1 = user1.user
JOIN table_1 user2 ON games.user_2 = user2.user
http://sqlfiddle.com/#!2/c855b/16
I just used #skishore's query, a bit fixed, because it is broken for draws. The one that takes draws under consideration would be
SELECT
case when user1.winnings > user2.winnings then user1.user
when user2.winnings > user1.winnings then user2.user
else null
end
FROM table_2 games
JOIN table_1 user1 ON games.user_1 = user1.user
JOIN table_1 user2 ON games.user_2 = user2.user
But apart from this, I still don't get the purpose. I wrote this in comment to #skishore answer, but paste it here also. Consider the case:
User c won 99 matches played with user b, user d on the other hand won 2 matches played with user c. But who will be the winner between c and d? C
The second question is - why do you need this stored in a separate table? Winnings number will be dynamically changing so you would have to create trigger to keep winner column on table2 up to date. Can't you just get winner using this query?

MySQL: Display one random result which a user has not voted on

I need help on displaying one random result in which the current user has not voted on.
Currently my database setup and the last query I have tried can be found on http://sqlfiddle.com/#!2/2f91b/1
Basically I can isolate each individual item using this query:
SELECT a.img_url, a.item_id, a.user_id, a.img_status, b.item_question, c.user_name, c.user_fbid, d.voter_id, count(d.img_id) AS totalVotes
FROM os_photos a
LEFT JOIN os_items b ON a.item_id = b.item_id
LEFT JOIN os_users c ON a.user_id = c.user_id
LEFT JOIN os_votes d ON a.img_id = d.img_id
GROUP BY a.img_id
ORDER BY RAND()
LIMIT 1
My Problem is: With the SQL knowledge that I have, I am unable to isolate the results to show only the rows in which user #2 has not voted on. I realize the problem is when I use group by, it combines the voter_id and therefore I am unable to check if user #2 has had any input for the item.
Example:
Item # | voter_id
1 | 2
1 | 3
2 | 2
3 | 1
3 | 4
4 | 3
4 | 1
5 | 1
5 | 2
With the above sample set, the resulting item should be either item #3, #4 or any other items which have not been voted on.
Your help, advise and knowledge is greatly appreciated.
To get the items that dont exist you need a LEFT JOIN with condition that would otherwise make a positive match, and then add a WHERE clause matching one of the resulting columns to NULL:
SELECT a.img_url, a.item_id, a.user_id, a.img_status, b.item_question, c.user_name,c.user_fbid, d.voter_id, count(d.img_id) AS totalVotes
FROM os_photos a
LEFT JOIN os_items b ON a.item_id = b.item_id
LEFT JOIN os_users c ON a.user_id = c.user_id
LEFT JOIN os_votes d ON a.img_id = d.img_id
LEFT JOIN os_votes d2 ON a.img_id = d2.img_id AND d2.voter_id=2
WHERE d2.voter_id IS NULL
GROUP BY a.img_id
ORDER BY RAND()
LIMIT 1

Select statement that that counts total number of distinct entries in one table, depending on data from another table

I have two tables: DATA and USERS
USERS
id sqft postal province city
==========================================================
1 1 Y7R BC Vancouver
2 2 Y7R BC Vancouver
3 1 L5B ON Toronto
and
DATA
id uid power
=======================
1 1 1000
2 2 1300
3 1 1500
uid in table DATA matches to id in table USERS
I want to be able to count the the number of distinct uid in DATA where the postal code is Y7R and sqft is 1
SELECT COUNT(id)
FROM `DATA` AS `d`
INNER JOIN `USERS` AS `u`
ON u.id=d.uid
WHERE u.postal='Y7R' AND u.sqft=1
GROUP BY u.id;
They should be distinct anyway if you have a proper schema, if so just remove the group by clause.
SELECT COUNT(DISTINCT D.UID) FROM DATA D
LEFT JOIN USERS U ON D.UID=U.ID
WHERE U.POSTAL='Y7R' AND U.SQFT=1)
In case you need distinct
You can use this solution:
SELECT COUNT(DISTINCT a.id)
FROM USERS a
JOIN DATA b ON a.id = b.uid
WHERE a.sqft = 1 AND
a.postal = 'Y7R'
Try this one:
SELECT COUNT(DISTINCT a.id)
FROM USERS a
INNER JOIN DATA b
ON a.id = b.uid
WHERE a.sqft = 1 AND
a.postal = 'Y7R'