Reputation: 3647
I have three tables:
user: id, name
keyword: id, name
userkeyword: id, user_id, keyword_id
I want to execute query in following way:
Display those users whose keyword/s are matched with the login user's keywords. In the order of maximum number of keyword matched user should display first
e.g : If userA having 4 matched keywords, userB having 8, userC having 1, userD having 6 then the result should be in the order of,
userB
userD
userA
userC
For that I have done with this query (assume login user's id is 1):
select *
from user
where id IN (
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc)
AND id != 1
Here the result is getting perfect but the order is not correct. I have merged two queries in following manner"
select *
from user
where id IN (?)
AND id!=1
+
select user_id
from userkeywords
where keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by user_id
order by count(keyword_id) desc
Second query returns user_id
in correct order but when I merged both queries, order was changed (wrong).
Hope I have mentioned my query properly with enough detail.
Upvotes: 1
Views: 58
Reputation: 1
You can join the tables and use GROUP BY
to count the number of keywords that match for each user. You could then sort by the count in descending order to get the users with the maximum number of keyword matches first. You don't really need to use subqueries for this. Take a look:
SELECT u.id, u.name, COUNT(*) as matched_keywords
FROM user AS u
JOIN userkeyword AS uk1 ON u.id = uk1.user_id
JOIN userkeyword AS uk2 ON uk1.keyword_id = uk2.keyword_id
WHERE uk2.user_id = 1
AND u.id != 1
GROUP BY u.id, u.name
ORDER BY matched_keywords DESC;
Upvotes: 0
Reputation: 2075
I would use an inner join to select the correct rows:
SELECT *
FROM user
INNER JOIN (
SELECT * FROM userkeyword
WHERE keyword_id IN (
SELECT keyword_id
FROM userkeyword
WHERE user_id=1
)
) uk
ON user.id = uk.user_id
GROUP BY u.id
ORDER BY count(*) DESC;
Upvotes: 0
Reputation: 2140
This should do it.
select uk.user_id, u.name
from userkeywords uk
left join user u on u.id = uk.user_id
where uk.keyword_id IN (
select keyword_id
from userkeywords
where user_id=1)
group by uk.user_id
order by count(uk.keyword_id) desc) AND uk.user_id != 1
Also, JOIN
provides better performance.
Upvotes: 0
Reputation: 238246
A subquery returns an unordered set, so the order by
in a subquery only matters for its limit
clause, if there is any. Any database other than MySQL would give an error message for a purely decorative sort order.
There's no way to sort on a column that only exists in the where
clause. You'd have to rewrite the query. One option is to replace your in
conditions with joins
:
select uk2.name
from userkeywords uk1
join userkeywords uk2
on uk1.keyword_id = uk2.keyword_id
and uk1.user_id <> uk2.user_id
join user u2
on u2.id = uk2.user_id
where uk1.user_id = 1
group by
uk2.name
order by
count(*) desc
Upvotes: 2