SELECT statement inside another SELECT statement - php

I have two tables called messages and users. In the messages table, there's a field which is a foreign key to the users table that is basically the users ID. I am trying to retrieve results from the messages table using a SELECT query, but I want the users username rather than their user ID. This SQL is wrong but I think it gets across the idea of what I'm trying to do:
SELECT (SELECT username FROM `users` WHERE u_id=?), message, sent FROM `messages` WHERE r_id=? AND sent > ?
Basically, I want to use the users ID stored in the messages table to get the users username to be returned AND get results from the messages table in one query.
I think JOINs are the tool for this, but I have very little bar no SQL experience.
Thanks.

You want to JOIN the two tables together, using the common u_id column.
SELECT u.username, m.message, m.sent
FROM messages m
INNER JOIN users u
ON m.u_id = u.u_id
WHERE m.r_id = ?
AND m.sent > ?

This is the case for an inner join:
select
u.username,
m.message,
m.sent
from
messages m
inner join users u on
m.u_id = u.u_id
where
m.r_id = ?
and u.u_id = ?
and m.sent > ?
What you're doing here is taking the messages table and saying, "Okay, grab me everything in the users table where the u_id column from messages equals the u_id column from users.
The where clause then filters your results down based on the parameters you want to pass it.
You can join tables ad nauseum, so you don't have to do just one, for future reference.
If you'd like to read more about joins and the different types, I highly encourage you to read Atwood's post on it here.

You can join two tables like this too:
SELECT
u.username,
m.message,
m.sent
FROM
messages m,
users u
WHERE
m.r_id=? AND
m.sent > ? AND
m.u_id = u.u_id
m.u_id is user id in messages table

You can refactor the query slightly like this:
select
u.username,
m.message,
m.sent
from
(
select u_id,message,sent
from messages
where r_id = ?
and sent > ?
) m
inner join
(
select u_id,username
from users
where u_id = ?
) u using (u_id);
You need to make sure you have a compound index on r_id and sent
ALTER TABLE messages ADD INDEX (r_id,sent);

Your query needs only slight correction and then it's equivalent to a LEFT JOIN (or INNER JOIN, exactly as #Joe Stefanelli's answer if messages.u_id is never NULL):
SELECT
(SELECT username FROM `users` WHERE u_id = messages.u_id) AS username
, message
, sent
FROM messages
WHERE r_id = ?
AND sent > ?

Related

Updating a row based on number of existing records

I'm trying to update a number of rows in a user table based on a value occurring more than once. In this case it's user email - as the user can sign up to multiple websites hosted in this application.
UPDATE users SET email = REPLACE(email,'#', CONCAT('+',user_id,'#'))
WHERE user_id IN (
SELECT user_id FROM users HAVING COUNT('email') > 1
);
This query gives me the following error;
ERROR 1093 (HY000): You can't specify target table 'customer_entity' for update in FROM clause
I've tried a number of variations but none of these seem to work.
MySQL does not support this syntax. Instead, you can self-join an aggregate query:
UPDATE users u
INNER JOIN (SELECT user_id FROM users GROUP BY user_id HAVING count(email) > 1) u1
ON u1.user_id = u.user_id
SET u.email = REPLACE(e.email,'#', CONCAT('+', u.user_id, '#'))
The two links I cited have lots of great suggestions, and GMB's suggestion sounds promising, too.
Q: Have you really looked at each of these (multiple different!) alternatives, and tried them out yourself, with your dataset? What happened?
SUGGESTION (taking GMB's example):
Verify the select works (returns one or more rows):
SELECT user_id FROM users GROUP BY user_id HAVING count(email) > 1)
Combine the "update" with the "join" (different syntax):
UPDATE users u1
SET u1.email = REPLACE(e.email,'#', CONCAT('+', u1.user_id, '#'))
INNER JOIN users u2
ON u1.user_id = u2.user_id
GROUP BY u2.user_id HAVING count(u2.email) > 1;
Please let us know the results.

SQL NOT query returns wrong results

I have 2 SQL tables. users contains users and registrants contains all the registrations done for an event. Given that I have the id of the event - I am successfully printing out those users that are registered for a specific event. However I want to print all the users that are NOT registered for the event and here I fail at producing the correct result. My query is as follows:
SELECT users.fName, users.lName, users.uid
FROM users, registrants
WHERE registrants.tourId = '$id' AND NOT registrants.pId = users.uid
The result of this is an array of 33 users printed out, although I have only 12, 3 of which are already registered for the event. Is the SELECT command wrong or I will need to dig into the php code, although I am pretty sure all the work there is correct.
By specifying no JOIN syntax, but instead specifying a kind of inequality join in the WHERE clause, you are effectively asking SQL to find all combinations of users and registrants, with the additional filter criteria in the WHERE clause, hence the large number of rows.
I believe the query you are looking for is more like this:
SELECT users.fName, users.lName, users.uid
FROM users
WHERE users.uid NOT IN (
SELECT registrants.pId
FROM registrants
WHERE registrants.tourId = '$id');
"Find all users, except those registered for tourId = '$id'"
Assuming that "registrants.pId" is the foreign key to the table "users", this request will give you every combination of registrants and users where the registrant and user are not related.
The way I see you could achieve the intended result is to select users using a subquery to exclude those who are regitered to the event. Which would look something like :
$query = "SELECT users.fName, users.lName, users.uid FROM users WHERE users.uid not in (SELECT users.uid FROM users, registrants WHERE registrants.tourId = '$id' AND registrants.pId = users.uid)"
there might be a simpler way to do this, though I do not see it right now.
Have you tried ".... AND registrants.pld <> users.uid"; ?
or
".... AND registrants.pld != users.uid";
You need to use an anti-join, that is, an outer join where you want to return from the dependent side of the join values where the independent side of the join is null.
In your case that looks like this:
SELECT users.fName, users.lName, users.uid
FROM users
LEFT OUTER JOIN registrants
ON users.uid = registrants.pId
AND registrants.tourId = '$id'
WHERE registrants.pId IS NULL

How to find total of records?

how can I find the total records in this case:
I have a table 'users', a table 'messages' and a table 'groups'. A user can sent a message, and that will be stored in the table 'messages'. Each user can be a member of one group. Now I would like to show the total messages sent by all users in the group on the group-details-page. How can I get all the users in the group and count their messages? What is the best and fastest way to do that?
I can't work with Joins, so this doesn't work. I don't know how to fix it.
SELECT COUNT(Message_id) AS total_messages, d.Userid FROM messages AS
d LEFT JOIN users AS s ON (s.Groupid=$groupid) WHERE
s.Groupid=$groupid
Thanks!
If you need table structure:
** users **
Userid
Groupid
** groups **
Groupid
Some_details
** messages **
Messageid
Userid
Subject
Content
If you're looking for total messages without needing to know per user, try
SELECT COUNT(messages.Messageid) as total_messages
FROM messages
INNER JOIN users ON messages.Userid = users.Userid
WHERE users.Groupid = $groupid
Make sure you're indexing the messages.Userid field as well if you'll be doing a lot of querying based on it.
Needing a count per user try
SELECT
COUNT(messages.Messageid) as num_messages,
messages.Userid
FROM messages
INNER JOIN users ON messages.Userid = users.Userid
WHERE users.Groupid = $groupid
GROUP BY users.Userid
If you want all users in a particular group with their total messages then try out this
SELECT messages.Userid, COUNT(messages.Messageid) as total_messages
FROM messages
INNER JOIN users ON messages.Userid = users.Userid
WHERE users.Groupid = $groupid GROUPBY messages.Userid
Select Groupid,Some_details,count(Messageid) as count_message from groups Left join users On
users.Groupid = groups.Groupid left join messages on messages.Userid = users.users.Userid GROUP BY Groupid

php/mysql join syntax

I have the userids of people who have joined a group in one table but not their names thatlie in another table. So I think I need to do a join. I'm starting with groupid that describes the grouop.
Table 1, groupmem has groupid and userid for the members.
Table 2, users has userid and username
The users table has every user. The groupmem only has some who have joined groups.
SQL statement should be something like following but can't get it to work.
select users.name
FROM users,groupmem
LEFT JOIN users
on groupmem.userid=users.userid
WHERE groupmem.groupid = 22
22 being some value..
Thinking maybe where clause is in wrong place or I am using wrong type of join but or not using on correctly but, in any case, can't get it to work. Thx for any suggestions:
Try:
SELECT u.username
FROM `users` u
LEFT JOIN `groupmem` g
ON u.userid = g.userid
WHERE g.groupid = 22
This should do the trick:
SELECT users.name
FROM groupmem
LEFT JOIN users ON groupmem.userid = users.userid
WHERE groupmem.groupid = 22
Your query seems to be quite right - assuming I guessed your table-structure right.

In MySQL how do I count messages from a user?

I have tables as below.
Table Messages
message_id
parent_id
forum_id
user_id
Table Users
user_id
username
pass
How to query a user, and display the count of their messages with their username?
My query:
select count(subject), user_id from messages group by user_id;
The problem is that it only displays user_id and count of messages but no username. How do I make it display the name of the user?
You need to join the users table into your query:
select count(*), username
from messages, users
where users.user_id = messages.user_id
group by users.user_id;
SELECT username, COUNT(*) FROM messages M
JOIN users U USING (user_id)
GROUP BY U.user_id
This takes care of a scenario where two different user_id have the same username in the users table. Also this query is MySQL specific and may not work with other RDBMS.
I think this is the query you want.
$query = "SELECT u.username, COUNT(*) as total_count FROM messages m INNER JOIN users u ON m.user_id = u.user_id GROUP BY U.user_id"
Here total_count gives the total count of messages grouped by user id to avoid joining of same usernames.
Use below. I believe it will work.
SELECT messages.user_id, users.username, count(*)
FROM messages, users
WHERE messages.user_id = users.user_id
Good Luck!!!

Categories