Mysql select alias in where clause - mysql

I have problem with using alias in where clause.
I have tables like this:
I store users and they can send messages to each other. Messages data is stored in social_messages table, with core_users_sender and core_users_receiver ids.
Now when user logs in system I want to show the list of only those users with which he/she had conversation.
(logged in core_users.id is 6)
I use this query and get ids of friends with which user had conversations without problem:
SELECT
messages.id,
messages.status,
messages.send_date,
IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
) as friend_id
FROM
social_messages messages
WHERE
messages.core_users_sender = 6
OR
messages.core_users_receiver = 6
GROUP BY
friend_id
But problem is that when I try to get data from core_users table with friend_id and and use query:
SELECT
messages.id,
messages.status,
messages.send_date,
IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
) as friend_id,
users.fullname
FROM
social_messages messages,
core_users users
WHERE
users.id = friend_id
AND
(
messages.core_users_sender = 6
OR
messages.core_users_receiver = 6
)
GROUP BY
friend_id
I get error because friend_id cant be used in where clause because its calculated in select

You can't uses aliases in the where clause. Use the original subquery
where users.id = IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
)
It is not allowable to refer to a column alias in a WHERE clause, because the column value might not yet be determined when the WHERE clause is executed.

I suggest you to reorder your query in this way :
SELECT
messages.id,
messages.status,
messages.send_date,
users.fullname,
IF(
messages.core_users_sender IS NOT NULL,
messages.core_users_receiver,
messages.core_users_sender
) as friend_id
FROM
social_messages messages
left join core_users users_sender
on users_sender.id = messages.core_users_sender
and messages.core_users_sender = 6
left join core_users users_receiver
on users_receiver.id = messages.core_users_receiver
and messages.core_users_receiver = 6
WHERE
users_sender.id IS NOT NULL OR users_receiver.id IS NOT NULL

You can alias your table and use it
SELECT messages.*, users.fullname
FROM
(SELECT
messages.id,
messages.status,
messages.send_date,
IF(
core_users_sender = 6,
core_users_receiver,
core_users_sender
) as friend_id
FROM
social_messages messages
WHERE
messages.core_users_sender = 6
OR
messages.core_users_receiver = 6
GROUP BY
friend_id) as `messages`
JOIN
core_users users
ON
users.id = messages.friend_id

Related

How to select sql data by using 2 join tables with OR condition without duplicate records

I have a mysql select statement as below:-
select user.username, chat.from_user,chat.to_user,chat.message,chat.date_created
from chat join user on (chat.from_user or chat.to_user) in (user.user_id)
where(chat.from_user = 3 or chat.to_user = 3) and chat.chat_id IN
(SELECT distinct (MAX(chat.chat_id) )
FROM chat GROUP BY chat_group_id);
and here is my result
I always get username = admin. My expectation result is username will get correct from / to user.
Please help. Thank you.
SELECT
IF(chat.from_user=3, to_user
, IF(chat.to_user=3, form_user, 0)) AS username,
chat.from_user,chat.to_user,chat.message,chat.date_created
FROM chat
LEFT JOIN user fr_user ON chat.from_user = user.user_id
LEFT JOIN user to_user ON chat.to_user = user.user_id -- since you only want to show the TO_USERNAME, you can remove above line
WHERE (chat.from_user = 3 OR chat.to_user = 3) and chat.chat_id
IN
(SELECT distinct (MAX(chat.chat_id) )
FROM chat GROUP BY chat_group_id);
I think you intend:
select u.username, c.from_user, c.to_user, chat.message, c.date_created
from chat c join
user u
on u.user_id in (c.from_user, c.to_user)
where 3 in (c.from_user, c.to_user) and
c.chat_id in (select max(c2.chat_id)
from chat c2
group by chat_group_id
);

Get conversation and last message Query

i'm tring to get the conversations with the relative last message and order them by time and if is read the message. Let's go to show the my logic.
I created 3 table: inbox_join / inbox_msg / users
On the first table "inbox join" i have the datas about who have a active discussion. In this case we have id_user - "1" and id_user_2 - "4" they have a conversation.
On the inbox_msg table I have the text message, id conversation where the message will shown and other field easy to understand.
Inbox join table
Inbox_msg table
Users table
I made a query that work fine, but the my issue is that i can't have the occured_at on the inbox_msg table. I would like find a better solution for have my desidered result and i can't order how i'm looking for.
This is my query
SELECT DISTINCT (
inbox_join.id_conversation
), user_chat.name AS name_conv, user_chat.surname AS surname_conv, user_chat.username as username_conv, user_chat.id as id_chat, image_upload.name_image, (
SELECT DISTINCT (
message
)
FROM inbox_msg
WHERE inbox_join.id_conversation = inbox_msg.id_conversation
ORDER BY occured_at DESC
LIMIT 1
) AS last_msg, users.name, users.surname
FROM inbox_join
INNER JOIN users ON users.id = inbox_join.id_user
INNER JOIN users AS user_chat ON user_chat.id <> 1 AND (inbox_join.id_user_2 = user_chat.id || inbox_join.id_user = user_chat.id)
INNER JOIN image_upload ON image_upload.id_image = user_chat.profile_image
WHERE inbox_join.id_user = 1
OR inbox_join.id_user_2 = 1
Result desidered selecting the conversation about user 1:
id_conversation | id_user | name | surname | username | last_msg | occured_at_last_msg | read_msg |
1 4 E S E Yes 1380724676 0
4 5 G E K Good 1380724675 0
Query:
SELECT im.id_conversation,
im.id_user,
u.name,
u.surname,
u.username,
im.message AS last_msg,
im.occured_at AS occured_at_last_msg,
im.read_msg
FROM inbox_msg im
JOIN users u
ON u.id_user = im.id_user
JOIN (SELECT id_conversation,
MAX(occured_at) AS occured_at
FROM inbox_msg
GROUP BY id_conversation) im2
ON im2.id_conversation = im.id_conversation
AND im2.occured_at = im.occured_at
ORDER BY im.occured_at DESC
I made this query and should work fine, I would like receive comment about this query.
SELECT DISTINCT (
im.id_conversation
), users.name, users.surname, users.username, image_upload.name_image, im.message as last_msg, im.occured_at, im.read_msg
FROM inbox_join
INNER JOIN (
SELECT sub . *
FROM (
SELECT DISTINCT (
id_conversation
), id_user, message, occured_at, read_msg
FROM inbox_msg
WHERE id_user <> 1
ORDER BY occured_at DESC
) AS sub
GROUP BY sub.id_user
ORDER BY sub.occured_at DESC
) AS im ON im.id_conversation = im.id_conversation
INNER JOIN users ON im.id_user = users.id
INNER JOIN image_upload ON users.profile_image = image_upload.id_image
WHERE inbox_join.id_user = 1 || inbox_join.id_user_2 = 1

MySQL nested ANDs and several conditions

I have two table for a multiple choice questionnaire (each user answers a series of questions):
users (userID, name, email)
votes (voteID, userID, questionID, answerID)
Sample data (users):
0, Some Name, some#thing.com
1, Other Name, some#one.com
Sample data (votes):
0, 1, 1, 1
1, 1, 2, 2
2, 1, 3, 2
I would like select all users who has the correct answers.
I tried this (where I've hardcoded the answers in):
$sql = "SELECT users.userID, users.name, users.email FROM users
INNER JOIN votes ON (users.userID = votes.userID)
WHERE (votes.questionID = '1' AND votes.answerID = '1')
AND (votes.questionID = '2' AND votes.answerID = '2')
AND (votes.questionID = '3' AND votes.answerID = '2')
AND (votes.questionID = '4' AND votes.answerID = '3')
AND (votes.questionID = '5' AND votes.answerID = '1')
GROUP BY users.userID";
But this doesn't return anything.
I've also tried something like this (where I've also hardcoded the answers in):
$sql = "SELECT users.userID, users.name, users.email FROM users
INNER JOIN transfertipsvotes ON (users.userID = transfertipsvotes.userID)
WHERE (transfertipsvotes.questionID = '1' AND transfertipsvotes.answerID = '1') GROUP BY users.userID
UNION
SELECT users.userID, users.name, users.email FROM users
INNER JOIN transfertipsvotes ON (users.userID = transfertipsvotes.userID)
WHERE (transfertipsvotes.questionID = '2' AND transfertipsvotes.answerID = '2') GROUP BY users.userID
UNION
SELECT users.userID, users.name, users.email FROM users
INNER JOIN transfertipsvotes ON (users.userID = transfertipsvotes.userID)
WHERE (transfertipsvotes.questionID = '3' AND transfertipsvotes.answerID = '2') GROUP BY users.userID";
But this just returns all users with one correct answer.
How do I make the correct query to select all users with the correct answers?
As far as I can see it now you need to use an INNER JOIN for each question, so each inner join will look like this:
INNER JOIN votes AS q1 ON (users.userID = q1.userID) AND q1.questionID = '1' AND q1.answerID ='1'
Repeat this for each question and you can check it.
If i understood you correctly, you want users who have answered all questions correct. In that case you should use INTERSECT instead of UNION
But for this you are hitting the table as many times as your questions. Its better to use OR clause in where "((question1 and Answer1) or (question2 and Answer2))". and at last do a group based on userid and get count of correct answer and fetch only those members whose has all correct answer.

MySql Query with UNION and SORT

Actually i am trying to create a conversation interface like FB(Messages) and for that a sql query is used to fetch all the persons whom with user is talked already.
I need the id of the user from whom he had talked in descending order,
Like if A has chatted with B and C. Then B AND C will be result of that query and B will come first because A chatted with B recently.
My 'messages' table structure is :
http://www.softnuke.com/me/files/DB.png
This is the FB example:
http://www.softnuke.com/me/files/msg.png
This is my incorrect query which needs to be fixed:
SELECT DISTINCT(`mates`)FROM(
SELECT `time` AS `time`,`from_id` AS `mates`
FROM `messages` AS T WHERE (`from_id`=$uid OR `to_id`=$uid)
UNION
SELECT `time` AS `time`,`to_id` AS `mates`
FROM `messages` AS T WHERE (`from_id`=$uid OR `to_id`=$uid)
) AS T
WHERE `mates`!='$uid'
ORDER BY `time`
$uid will give me the variable of the user I want to fetch List(Here its A).
You seem to be getting the main person and the person they were talking to, irrespective of which one is the main person. Also not quite sure how MySQL will work out the time to order things by when you are using DISTINCT which will remove some of the records with their times.
You could get the max time and order by that:-
SELECT `mates`, MAX(`time`) AS LatestConv
FROM(
SELECT `time` AS `time`,`from_id` AS `mates`
FROM `messages` AS T WHERE `to_id`=$uid
UNION
SELECT `time` AS `time`,`to_id` AS `mates`
FROM `messages` AS T WHERE `from_id`=$uid
) AS T
GROUP BY `mates`
ORDER BY LatestConv
To get the status of that latest message:-
SELECT a.mates, a.LatestConv, IFNULL(b.Status, c.Status)
FROM
(
SELECT mates, MAX(`time`) AS LatestConv
FROM(
SELECT `time` AS `time`, from_id AS mates
FROM messages AS T
WHERE to_id = $uid
UNION
SELECT `time` AS `time`, to_id AS mates
FROM messages AS T
WHERE from_id = $uid
) AS T
GROUP BY `mates`
) a
LEFT OUTER JOIN messages b
ON a.mates = b.from_id AND a.LatestConv = b.`time` AND b.to_id = $uid
LEFT OUTER JOIN messages c
ON a.mates = c.to_id AND a.LatestConv = c.`time` AND c.from_id = $uid
ORDER BY LatestConv
Note that this might get a touch confused if there are multiple messages to the same person which all share the same latest time. If this is likely it could be coped with as follows:-
SELECT a.mates, a.LatestConv, MAX(IFNULL(b.Status, c.Status))
FROM
(
SELECT mates, MAX(`time`) AS LatestConv
FROM(
SELECT `time` AS `time`, from_id AS mates
FROM messages AS T
WHERE to_id = $uid
UNION
SELECT `time` AS `time`, to_id AS mates
FROM messages AS T
WHERE from_id = $uid
) AS T
GROUP BY `mates`
) a
LEFT OUTER JOIN messages b
ON a.mates = b.from_id AND a.LatestConv = b.`time` AND b.to_id = $uid
LEFT OUTER JOIN messages c
ON a.mates = c.to_id AND a.LatestConv = c.`time` AND c.from_id = $uid
GROUP BY a.mates, a.LatestConv
ORDER BY LatestConv

MySQL GROUP BY / ORDER BY issue with flat messages table / threads

Ok, I'm trying to base something similar off of this, but not quite getting it nailed: GROUP BY and ORDER BY
Basically, wanting a query to find the latest messages in each 'thread' between the current logged-in user and any other users, but via a flat (non-'threaded') table of messages:
messages {
id,
from_uid,
to_uid,
message_text,
time_added
}
Assuming the current user's uid is '1', and the latest message in each 'thread' could either be from that user, or to that user (the other party always denoted by thread_recipient):
SELECT a.*,thread_recipient
FROM messages a
JOIN (SELECT IF(from_uid = '1',to_uid,from_uid) AS thread_recipient,
MAX(time_added) AS recency
FROM messages
WHERE (from_uid = '1' OR to_uid = '1')
GROUP BY thread_recipient) b ON thread_recipient = (IF(a.from_uid = '1',a.to_uid,a.from_uid))
AND b.recency = a.time_added
ORDER BY a.time_added DESC
But I fear this ain't gonna work right, and maybe messages sent at the same time might end up being returned for the wrong user?
Is my WHERE condition misplaced?
Any wisdom much appreciated.
Here's an idea: take the UNION of the following two queries, then get
the maximum dates from the result.
SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
When you do the following:
SELECT MAX(time_added),other_party
FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
UNION
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
) MyMessages
GROUP BY other_party
You will get the most recent time associated with a message sent to
each person that user '1' is corresponding with. Then you can join the
results of that to the original messages table to get what you want:
SELECT Messages.*
FROM (SELECT MAX(time_added) AS MaxTime,other_party
FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
UNION
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
) MyMessages
GROUP BY other_party
)
JOIN Messages
ON (Messages.time_added = MyMessages.MaxTime AND
(Messages.to_uid = MyMessages.other_party AND Messages.from_uid = '1' OR
Messages.from_uid = MyMessages.other_party AND Messages.to_uid = '1')
)
Try this - I think it gives you what you are looking for more simply and efficiently.
SELECT latest_time = MAX(a.time_added, b.time_added)
FROM messages a, messages b
LEFT JOIN messages a1
ON a1.from_uid = a.from_id
-- find the case where the following doesn't exist
-- so you know there is nothing after b1
LEFT JOIN messages a2
ON a2.from_uid = a.from_id
AND a2.time_added > a1.time_added
LEFT JOIN messages b1
ON b1.to_uid = b.to_id
LEFT JOIN messages b2
ON b2.to_uid = b.to_id
AND b2.time_added > b1.time_added
WHERE a.from_id = '1'
AND b.to_id = '1'
AND c1.id IS NULL
AND c2.id IS NULL
ORDER BY a.time_added DESC
Ok, after comments - if id is autoincrement use it instead of message time. But you have propoer condition to ensure that messages will not be delivered to wrong persons.