Select entries that aren't part of a pair in another table - mysql

Tables:
users friends
+-------+----+ +-----+-----+
| name | id | | id1 | id2 |
+-------+----+ +-----+-----+
| user1 | 1 | | 1 | 2 |
+-------+----+ +-----+-----+
| user2 + 2 |
+-------+----+
In my database id1 in the friends table is the dominant column, which means that if id1 = 1 and id2 = 2 then user1 is friends with user2 but not the other way around.
I'm trying to select all users from the users table that don't have X as id1 in friends. This is because I don't want userX to be able to find friends that he's already added.
Here is my failed attempt:
SELECT * FROM users LEFT JOIN friends ON users.id != friends.id2 WHERE friends.id1 = X AND users.id != X;
I added users.id != X since we don't want to return the user himself in a search for other users.

You can use an outer join to do that, you attempt went into the right direction:
select u.*
from users u
left join friends f
on u.id = f.id2
where f.id1 is null
An outer join returns NULL for every non-matched item at least.

using not in() (more efficient than not exists() in mysql)
select *
from users
where id != xi
and id not in (
select id.2
from friends
where friends.id1 = x
)
using not exists()
select *
from users
where id != x
and not exists (
select 1
from friends
where friends.id1 = x
and friends.id2 = users.id
)

Related

MySQL query from data normalized tables

I have three tables:
users
user_id username
---------------------
1 | mrzander
2 | foo
3 | bar
---------------------
interests
interest_id interest
------------------------
1 | cars
2 | power tools
3 | shaving
4 | phones
5 | computers
------------------------
user_interests
id uid iid
-----------------
1 | 1 | 2
2 | 1 | 4
3 | 2 | 3
4 | 1 | 5
-----------------
Basically, I have a table of users, a table of interests, and a table that shows what users have what interests. If I know what user id I want the interests from, what query would give me all of a particular users interests?
In this example, what query would return a table called "Interests" that tells me user_id = 1 likes power tools, phones, and computers?
If you want the result on same row you should use join and group concat
select c.username, group_concat( b.interst)
from user_interest as a
left join interest as b on a.iid = b.interest_id
left join users as c. on c.user_id = a.uid
where c.user_id = 1
group by c.username
or if you need result on different rows se join only
select c.username, b.interst
from user_interest as a
left join interest as b on a.iid = b.interest_id
left join users as c. on c.user_id = a.uid
where c.user_id = 1
Simply join the two tables.
select i.*
from interests i
join user_interests u
on u.iid = i.interest_id
where i.uid = 1;

MySQL: Cross match records from two different columns

I got table Followers which looks like this:
| id | follower_id | user_id |
| 1 | user1 | user2 |
| 2 | user2 | user3 |
| 3 | user2 | user1 |
| 4 | user4 | user3 |
| 5 | user3 | user2 |
I need to count instances when two users are following each other, in this case result should be 2, because user1 and user2, user2 and user3 is following each other.
I tried all sorts of combinations of LEFT JOIN, SELECT COUNT() FROM table WHERE field IN(), but I think I'm missing something... I feel though that I'm close to the goal with this query
SELECT
u.id,
u.name,
u.img,
ifnull((follower_id and user_id),0) as `match`
FROM table_users u
LEFT JOIN (select user_id from table_followers where follower_id = 14) followers on u.id = followers.user_id
LEFT JOIN (select follower_id from table_followers where user_id = 14) following on u.id = following.follower_id
WHERE u.id = 14 and (follower_id or user_id)
With this query I'm trying to figure out how many followers user_id_14 has.
Is it possible to achieve this with pure MySQL, or I should go around this with PHP loops?
This is making a headache to me for three hours and I can't find solution.
SELECT
CONVERT(COUNT(*)/2, UNSIGNED) as counter
FROM followers u
INNER JOIN (
select
user_id,
follower_id
from followers
) as f
on u.user_id = f.follower_id
WHERE u.follower_id = f.user_id
This may help you..
Select count(*)
From followers f1
joins followers f2 ON f1.follower_id = f2.user_id
and f1.user_id= f2.followerid;

mysql select a value within a select

I have an implementation messages system.
My problem is, I would like to know whether a user already has a thread with another user and if so what is the mid
I have a messages_recips table which look like this
---------------------------
| mid | seq | uid | status|
|--------------------------
| 4 | 1 | 1 | A |
| 4 | 1 | 2 | A |
---------------------------
if user id 1 having a thread with user id 2 I hold 2 rows with same mid.
I know I can create 2 sqls to achieve what I'm asking for, but I'm trying to do it in 1 sql.
As noted by Waqar Janjua, the key to this is a self-join query:
SELECT m1.mid
FROM messages_recips AS m1
JOIN messages_recips AS m2 ON m1.mid = m2.mid
WHERE m1.uid = 1
AND m2.uid = 2
I think you have to write a self-join query:
Select u.uid, u1.uid from tablename u
INNER JOIN tablename u1 on u.mid = u1.mid
You will get all the users who have the same mid.
In order to get only user1 and user2 records you have to place a where clause at the end of the query lik this.
Select u.uid, u1.uid from tablename u
INNER JOIN tablename u1 on u.mid = u1.mid
Where ( u.uid In ( 1,2 ) OR u1.uid In ( 1,2 ) ) ;

Query to find all no associated entities

I have two tables, USERS and USERS_ASSOCIATIONS
For simplistic sake they look like this
USERS USERS_ASSOCIATION
----- --------------------------
|id | |id |fk_id| fk_assoc_id |
----- --------------------------
| 1 | | 1 | 1 | 2 |
| 2 | | 2 | 1 | 3 |
| 3 | --------------------------
| 4 |
-----
users can be associated to each other so for this example user with ID of 1 is associated to user 2 and 3 but not to 4.
I am trying to create a query that will find all users that are not associated to a specific user. So for the example of user 1 the result of the query will be 4 , if the user were 2 then the result of the query would be 1 , 3 , and 4 because user two has no associations.
So far have have this
SELECT * from USERS WHERE AND USERS.id <> ( SELECT * FROM USERS_ASSOCIATION as UA INNER JOIN USESR as U ON UA.fk_assoc_id = U.id AND UA.fk_id = 1);
I know this is wrong, the sub query returns a list of all of the USER_ASSOCIATIONS that are found for a particular user.
Looks like you just need a "not in" rather than the "<>"... This should return the list of users that "are not in" the subquery.
SELECT *
from USERS
WHERE AND USERS.id not in ( SELECT * FROM USERS_ASSOCIATION as UA INNER JOIN USESR as U ON UA.fk_assoc_id = U.id AND UA.fk_id = 1);
select *
from USERS
where id <> 1
and id not in (select fk_id from USERS_ASSOCIATION where fk_assoc_id = 1)
and id not in (select fk_assoc_id from USERS_ASSOCIATION where fk_id = 1)

Selecting with subqueries in MySQL (Subqueries with ANY, and IN)

Thanks for the great answers!
For More Information
More info on MySQL IN comparison operator
Joining Tables
Subqueries with ANY, IN, and SOME
This is hard to explain, so lets set the stage...
userActions userGroupMap
+------+--------+ +------+-------+
| user | action | | user | group |
+------+--------+ +------+-------+
| x | acted! | | x | a |
| y | acted! | | y | a |
| y | acted! | | z | b |
| z | acted! | +------+-------+
| y | acted! |
| z | acted! |
| x | acted! |
| z | acted! |
+------+--------+
I want to select group a's actions. My idea was to
SELECT actions, user FROM userActions
WHERE user = (SELECT user, group FROM userGroupMap WHERE group = a)
But obviously this subquery returns more than one row. Should I use a JOIN?
Subquery returns more than 1 row
One approach is this:
SELECT actions,
user
FROM userActions
WHERE user IN
(SELECT user
FROM userGroupMap
WHERE [group] = 'a'
);
However, with large tables, this query tends to be inefficient and doing a join is better:
SELECT actions,
userActions.user
FROM userActions
INNER JOIN
(SELECT user
FROM userGroupMap
WHERE [group] = 'a'
) AS tmp
ON userActions.user = tmp.user;
Alternatively, as Jonathon mentioned, you could have done this and its pretty much as efficient, if not more:
SELECT actions,
userActions.user
FROM userActions
INNER JOIN userGroupMap
ON userActions.user = userGroupMap.user
WHERE [group] = 'a';
SELECT actions, user FROM userActions
WHERE user IN (SELECT user FROM userGroupMap WHERE group = a)
SELECT actions, user FROM userActions
WHERE user = ANY (SELECT user FROM userGroupMap WHERE group = a)
(Amended: only the user column should be returned, as noted by others.)
Actually, this query will give you what you need:
SELECT actions, user
FROM userActions
WHERE user IN
(SELECT user FROM userGroupMap WHERE group = 'a')
Couldn't you just do something like:
SELECT
a.actions,
a.user
FROM
userActions a
INNER JOIN userGroupMap g
ON a.user = g.user
WHERE
g.group = 'a'
Rather use join than subquery:
SELECT
userActions.action,
userActions.user
FROM
userActions
CROSS JOIN userGroupMap ON
userGroupMap.user = userActions.user AND
userGroupMap.group = 'a'
SELECT actions, user FROM userActions
WHERE user = (SELECT user FROM userGroupMap WHERE group = a)
The subquery was returning user and group (two fields) when it should be returning just user.