MySQL combing results - mysql

I have a table users and I have a simple search query:
SELECT *
FROM users
WHERE username LIKE 'rya%'
LIMIT 10
I also have another table called follows which basically is a list of users being followed by other users. I modified the above query to search only within what particular user is following:
SELECT users.*
FROM follows
INNER JOIN users ON users.id = follows.following_id
WHERE username LIKE 'rya%' AND follows.follower_id = 18
LIMIT 10
Most of the times, the query above only returns couple of results (because I am not search the entire users table).
What I want to do is combine the above 2 queries, to return a MAXIMUM of 10 results of usernames matching a certain string with first listing the user's following, and then search the entire table of users.
I already have a solution but it requires doing this at application level by first running the 2nd query, then first, and coming the two. Is there a way I can do all of this in 1 query?
Thanks

One way to do this is to search the entire user table, but order the results so that followers show up first. It's a little bit hard to understand what you want without schema, sample data, and output, but something like
SELECT users.*
FROM users
LEFT JOIN follows ON users.id = follows.following_id
WHERE username LIKE 'rya%'
ORDER BY follows.follower_id = 18 DESC
LIMIT 10
Notice that I used a LEFT JOIN in order to get all of the users. A different way would be to UNION the results of the two tables and wrap in a SELECT. I don't know why you would do it this way given the other option, but it would be something like
SELECT *
FROM (
SELECT users.*
FROM follows
INNER JOIN users ON users.id = follows.following_id
WHERE username LIKE 'rya%' AND follows.follower_id = 18
LIMIT 10
UNION
SELECT *
FROM users
WHERE username LIKE 'rya%'
LIMIT 10
) AS u
LIMIT 10
edit
Since the second one is working for you, I thought I throw a variation up using UNION ALL, which can be faster than UNION because it does not remove duplicate rows. You would have to make sure there were no duplicates yourself, which we can do like this
SELECT *
FROM (
SELECT users.*
FROM follows
INNER JOIN users ON users.id = follows.following_id
WHERE username LIKE 'rya%' AND follows.follower_id = 18
LIMIT 10
UNION ALL
SELECT users.*
FROM follows
INNER JOIN users ON users.id = follows.following_id
WHERE username LIKE 'rya%' AND follows.follower_id != 18
LIMIT 10
) AS u
LIMIT 10

Related

SQL - Joining 2 tables, show all from tbl1 and data from tbl2 depending on condition

Im trying to show a full list of all users in my DB aswell as extra information from a second table depending on whether they have a record in the second table
Im using MySQL, ive tried a few left join/right join union combos but nothing i have works
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
LEFT JOIN success ON users.id = success.userid
where docreqid IS NULL
union
SELECT users.id, users.name, success.URL_ID, success.docreqid FROM users
RIGHT JOIN success ON users.id = success.userid
where docreqid = 1;
I have a small table of 10 users. Only one user in my db has a record in the success tbl against docreqid '1'.
I want a table of ALL users and the URL_ID for their form if they have submitted it.
The above code works perfectly for this.
If i change the last line to:
where docreqid = 2;
I only get 9 results (the user with a record for docreqid '1' is missing).
I would like this table to show all 10 users and 'NULL' in the URL_ID & docreqid columns until they have completed the required action.
A left join should do what you want:
SELECT u.id, u.name, s.URL_ID, s.docreqid
FROM users u LEFT JOIN
success s
ON u.id = s.userid AND s.docreqid = 1;
The LEFT JOIN returns all rows in the first table -- no WHERE is filtering results. The ON only matches rows in success that meet the additional condition in the ON clause.

Mysql join two tables and limit by and order one table

i am only starting to play with MySQL and i seem to have been stumped by one problem.
I have 2 tables that I have left joined them with the part of working but it's not enough. I want them be order by id in one table by top and down this table messages
Example
table chat
id
1
2
3
table messages
chat_id
1
2
3
SELECT *
FROM (SELECT * FROM `messages` ) AS m LEFT JOIN
chat as c
ON m.chat_id = c.id
WHERE c.one ='$user_id' OR c.two = '$user_id'
GROUP BY c.id, m.chat_id
ORDER BY m.dates DESC
LIMIT 8
Are you trying to get a list of chats with the most recent message from each chat?
If so, your best bet is to add a column to the chat table and include a 'latest_message_id' so you can query like this:
SELECT * FROM chat LEFT JOIN messages ON messages.id = chat.latest_message_id
Otherwise you will need to run a really big subquery which will waste lots of CPU and memory

MySQL query based on condition from another table

I am trying to write a MySQL query that selects 10 usernames based on a condition evaluated from another table.
The result will be 10 usernames as suggestions to follow. So, I need to select 10 usernames that are currently not being followed by the logged user.
The below returns users that are already followed, so there is something wrong with it. Any idea how to fix that ?
"SELECT username
FROM users
WHERE NOT EXISTS
(
SELECT id
FROM user_followers
WHERE user_followers.user_followed_id = users.username AND user_followers.user_follower_id = ?
)
ORDER BY followers DESC LIMIT 10 "
user_followed_id - username of user being evaluated from the outer query.
user_follower_id - username of user for which the check is made (uses prepared statements)
Maybe try LEFT JOIN
SELECT *
FROM users u
LEFT JOIN user_followers uf
ON u.username = uf.user_followed_id
AND uf.user_follower_id <> ?
I hope this Helps:
SELECT username
FROM users
WHERE username NOT EXISTS
(
SELECT user_followers.user_followed_id -- I see in you code below that you use this to store the username
FROM user_followers
WHERE user_followers.user_follower_id = ?
)
AND username <> ? -- if the parameter is not the username,may be changed by the id column name of the user
ORDER BY followers DESC LIMIT 10

Select most recent entries and join with another table

My sql's rusty. I need to select the 30 most recent messages (those with the 30 largest id's), and then use the sender_id to join with the users table id.
In English, I want the users who sent the last 30 messages.
Here my query (which doesn't run):
SELECT * FROM group_messages
WHERE group_id=52
ORDER BY id DESC
LIMIT 30
LEFT JOIN users
ON users.id=group_messages.sender_id
If there's a better approach to this kind of query, then by all means.
Note: The first part works in selecting the 30 most recent messages. The trouble came when I tried joining on the users table. (And I just realized even if this query did run, I would need to add GROUP BY users.id a user may have sent more than 1 of the 30 most recent messages.
The JOIN clause has to come before WHERE, ORDER BY, and LIMIT
SELECT DISTINCT id
FROM (
SELECT u.id
FROM group_messages AS g
INNER JOIN users AS u on u.id = g.sender_id
WHERE group_id = 52
ORDER BY id DESC
LIMIT 30) AS x
I put it in a subquery so I could then perform the DISTINCT selection. If you do that in the same query, it will get rid of the duplicates before selecting the most recent 30 rows, so you'll get the 30 most recent senders, not the senders of the 30 most recent messages.
I doubt you really need a LEFT JOIN instead of INNER JOIN. That would only be needed if a message could have a sender ID that isn't in users.

MySQL COUNT with and without a HAVING clause

I need to know the COUNT of a query, and also the same query with a HAVING clause
By way of illustration (not the real case, but illustrative), if table pupilTable contains a list of pupil and their class, and I want to know the number of classes, and also the number of classes with more than 25 children:
I know I can get the total number of classes using:
SELECT COUNT( * ) AS NumAllClasses FROM pupilTable GROUP BY class
I know I can get the number of big classes with the condition using:
SELECT COUNT( * ) AS NumBigClasses FROM pupilTable GROUP BY class HAVING COUNT(pupil) > 25
Is there a simple (single query) way of getting both at the same time? Google has not been my friend :(
Edited to add illustrative data
Without any verification:
SELECT COUNT(*) AS count1 FROM table WHERE condition UNION ALL
SELECT COUNT(*) AS count2 FROM table WHERE condition HAVING second-condition
But note that i guess the second label will get lost so you will have both count-nrs returned under the label count1
You can user the following query:
select count(users.id) count1, count(u.id) count2 from users left join users u on users.id = u.id and u.fname = "abc" where users.id > 10
Here, I have used two conditions. You need to make relevant changes in this query to get desired output.
Here, user. and u. are the conditions.
In above query,
user.<condition1> : u.fname = "abc"
u.<condition2> : users.id > 10