I have a problem getting this query to work, so the basic idea is:
I have messages table, I want to track whether user has read a message or not. Note: multiple users can receive same message, so simply adding column read to message is not an option
Each message is in a thread (has a column thread_id)
I have another table user_read_message which adds record whenever somebody reads a message (user_id, message_id, read)
I want to get number of unread messages for a user in a specific thread. I was trying something along these lines but I couldn't get it to work:
SELECT m.thread_id, urm.user_id, urm.read
FROM sup_messages as m
LEFT OUTER JOIN user_read_message as urm ON m.id = urm.message_id
WHERE m.thread_id = 76852 AND urm.user_id = 1337;
Which would if it worked selected all messages in thread_id 76852 then joined user_read_message where user_id is 1337 and messages which he hasn't read will simply have null. I would then somehow count where read is 0 or NULL.
ps. If there is better idea how to model this please let me know!
I would do this. Add your WHERE clause related to the user_read_message table into the JOIN to that table. Since this is a LEFT JOIN, all of the fields returned from that table will be NULL if there is no match. Add a field from that table to your WHERE clause that is always populated and then check to see if it is NULL. That would mean there is no match.
SELECT m.thread_id, 1337 AS user_id, COUNT(*) unread_messages
FROM sup_messages as m
LEFT OUTER JOIN user_read_message as urm
ON m.id = urm.message_id
AND urm.user_id = 1337
WHERE m.thread_id = 76852 AND urm.message_id IS NULL;
SELECT COUNT(*)
FROM sup_messages
WHERE sup_messages.thread_id = 76852 AND
sup_messages.id IN (SELECT DISTINCT urm.message_id
FROM urm
WHERE urm.user_id = 1337 AND urm.read = 0)
Related
I'm trying to add an additional WHERE condition with AND to my mySQL query but keep getting the error The multi-part identifier userR.externalSource could not be bound
I have the alias setup in my left join from my other table but still I get this error. Could someone explain me why this is happening. I found article but this does not seem to be the case. I think it's rather a formatting issue of my query.
This query just counts 2 different groups of users but they can't have an empty (NULL) field for the externalSource field from the dbo.AAA_users table.
SELECT SUM(A.ROLECOUNT) AS 'Advanced Users' ,
(SELECT SUM(A.ROLECOUNT)
FROM (
SELECT role.logicalName AS Role_name ,
COUNT(DISTINCT users.userId) AS RoleCount
FROM dbo.AAA_UserRoleResource AS users
LEFT JOIN dbo.AAA_Role AS role ON role.roleId = users.roleId
LEFT JOIN dbo.AAA_User AS userR ON userR.userId = users.userId
GROUP BY role.logicalName
) A
WHERE A.Role_name IN ('ROLE_VIEWER', 'ROLE_USER')
AND userR.externalSource is not NULL <-- issue here
) AS 'Basic user'
FROM(
SELECT role.logicalName AS Role_name ,
COUNT(DISTINCT users.userId) AS RoleCount
FROM dbo.AAA_UserRoleResource AS users
LEFT JOIN dbo.AAA_Role AS role ON role.roleId = users.roleId
LEFT JOIN dbo.AAA_User AS userR ON userR.userId = users.userId
GROUP BY role.logicalName
) A
WHERE A.Role_name IN ('ROLE_ADMIN');
Any help appreciated.
So i figured out why it was not working.
I was adding the additional WHERE condition outside of the parenthesis and because of this it did not find the identifier which is within the parenthesis.
Here is the situation, i for the tables forum_topics, forum_replies and users.
Where the _topics contains all the topics, the _replies contains all posts and the users contain all users.
I'm trying to list the topics as:
(Subject)__________________________________(Time of last reply)
(Topic created by username)__________________(Last reply by)
For now, the "subject" and "topic created by username" displays just fine, however, the time of the last post and user who posted it is wrong.
SQL:
SELECT
forum_topics.id,
forum_topics.category,
forum_topics.subject,
forum_topics.created AS topiccreate,
forum_topics.createdby AS topiccreatedby,
forum_replies.topic,
forum_replies.created AS repliecreated,
forum_replies.createdby AS repliecreatedby,
usertopic.firstname AS topicfirstname,
usertopic.lastname AS topiclastname,
userreplie.firstname AS repliefirstname,
userreplie.lastname AS replielastname,
usertopic.id as topicid,
userreplie.id
FROM forum_topics
JOIN forum_replies ON forum_replies.topic = forum_topics.id
JOIN users usertopic ON forum_topics.createdby = usertopic.id
JOIN users userreplie ON forum_replies.createdby = userreplie.id
WHERE forum_topics.category = '1'
GROUP BY forum_replies.topic
ORDER BY forum_replies.created DESC
How can i get the "Time of last reply" and "Last reply by" to display correct? I've tried removing the Group By, and then it retrieves all the posts, however i just want the very latest post-data for each topic.
As for now when using GROUP BY, it retrieves all the topics just once (correct) but the last reply by and time of the last reply is not displaying correct as it seems to retrieve the data for the first post of each topic.
Hope you understand my question! :/
You need one more condition to get the latest reply. Here is how you would do it in the join clause:
FROM forum_topics
JOIN forum_replies ON forum_replies.topic = forum_topics.id
JOIN users usertopic ON forum_topics.createdby = usertopic.id
JOIN users userreplie ON forum_replies.createdby = userreplie.id
JOIN (select topic, max(created) as maxcreated
from forum_replies
group by topic
) frmax on frmax.topic = forum_replies.topic and
frmax.maxcreated = forum_replies.created;
I don't think you will need the group by after doing this.
Try removing both group by and order by in your SQL query and check.
I am building a messaging system and need to extract only the last message from each sender to a specified recipient. So, if 3 people each sent 5 messages(total of15 messages) to the recipient, I need to get 3 entries; the last message from each sender.
Here is my current SQL:
SELECT
messages.*,
user_accounts.uacc_id,
user_accounts.uacc_username,
user_profiles.upro_image_name
FROM messages
LEFT JOIN user_accounts
ON messages.msg_from_uacc_fk = user_accounts.uacc_id
LEFT JOIN user_profiles
ON user_profiles.upro_uacc_fk = user_accounts.uacc_id
WHERE
messages.msg_to_uacc_fk = ?
ORDER BY
msg_id
DESC
I tried adding 'MAX(1)' to the SELECT as well as 'LIMIT = 1' to after the DESC, but, of course, this just returned a total of 1 message.
It is sometimes hard to guess how the tables are designed but this query below uses a subquery to get the latest message for each user.
SELECT a.*,
c.uacc_id,
c.uacc_username,
d.upro_image_name
FROM messages a
INNER JOIN
(
SELECT msg_from_uacc_fk, MAX(msg_id) max_id
FROM messages
GROUP BY msg_from_uacc_fk
) b ON a.msg_from_uacc_fk = b.msg_from_uacc_fk AND
a.msg_id = b.max_id
INNER JOIN user_accounts c
ON a.msg_from_uacc_fk = c.uacc_id
INNER JOIN user_profiles d
ON d.upro_uacc_fk = c.uacc_id
WHERE a.msg_to_uacc_fk = ?
If this doesn't solve the problem, please add sample records along with your question :)
Can you not simply use a group by?
SELECT u.uacc_username, max(m.msg_id) as LatestMsg
FROM messages m JOIN user_accounts u on m.msg_from_uacc_fk = u.uacc_id
WHERE m.msg_to_uacc_fk = ?
GROUP BY u.uacc_username
I have 3 different tables:
Messages, Comments and Avatar.
What I would like to do is the following:
Get all Messages in the database, counting for each message the comments and showing the avatar of each user.
This is how the tables are built:
Messages -> messages_id, user_id, title, message
Comments -> comments_id, messages_id, comment
Avatar -> avatar_id, user_id, avatar
I tried the following:
SELECT *, COUNT(comments.comments_id) AS commentCount
FROM messages
LEFT JOIN comments ON messages.messages_id = comments.messages_id
LEFT JOIN avatar on messages.user_id = avatar.user_id
But I get only one row for the messages, the rest is not visible.
Any idea what I'm doing wrong here?
You need to use the GROUP BY:
SELECT messages_id
, title
, message
, user_id
, avatar_id
, avatar
, count(*) as commentCount
FROM messages
inner join avatar on messages.user_id = avatar.user_id
left join comments on messages.messages_id = comments.messages_id
GROUP BY messages_id
This should work if:
messages_id is unique in messages
user_id is unique in avatar
Otherwise you need to specify the value you want to get.
Edited:
I wrote inner join for avatartable thinking in that all users have an avatar. If this is not true should be left join like in your query.
Second try
Maybe the error was that the group by should be messages.messages_id instead of messages_id. In fact in others RDMBS this is an error:
ERROR: column reference "messages_id" is ambiguous
I'm going to be more precise:
SELECT m.messages_id as id
, min(m.title) as title
, min(m.message) as message
, min(m.user_id) as user_id
, min(a.avatar_id) as avatar_id
, min(a.avatar) as avatar
, count(c.comments_id) as commentCount
FROM messages as m
left join avatar as a on m.user_id = a.user_id
left join comments as c on m.messages_id = c.messages_id
GROUP BY m.messages_id
All the mincould be deleted in MySQL if you are sure there is only one value. In standard SQL you must choose the value you want, if there is only one you can type min or max.
I change join with avatar to be left join. Probably not all users have an avatar.
I am trying to write a sql statement to retrieve all the messages with user_id_user = '3' and status = '2' but I get repeated records I dont know why, I am stuck with it
My tables are this
message
id_message title content date user_id_user status
-------------------------------------------------------------
user
id_user name
----------------
message_has_user
message_id_message user_id_user
----------------------------------
my mysql query but I get repeated records I dont know why, I am reading tutorial also any help really appreciated
SELECT
message.title,
message.content,
message.date,
message.id_message,
message_has_usuario.user_id_user,
message.status,
user.name
FROM
message ,
message_has_usuario
INNER JOIN user ON message_has_usuario.user_id_user = '3'
WHERE
message.status = '2'
You're getting a Cartesian product because you're not joining all your tables accurately.
You're joining USER and MESSGAE_HAS_USERIO but you're not doing any joins on MESSAGE
Quick Example _ I assume those relationships are correct.
SELECT *
FROM Message M
INNER JOIN Message_Has_User MAU on M.MessageID = MAU.MessageID
INNER JOIN User U ON MAU.UserID = U.UserID AND U.UserID = M.User_Id_User
WHERE MAU.userID = '3'
AND M.Status = '2'
I neither endorse or will admit that I used a Select *. Darn it all to heck that I even wrote it. /hides
Try this:
...
FROM message
JOIN message_has_usuario
on message_has_usuario.message_has_usuario = message.message_has_usuario
...
select message.*
from message, user
where user.id = 3
and user.id = message.user_id_user
and message.status = 2
Your not using INNER JOIN correctly. This should work for you!! Also what is the point of the message_has_user table? I looks redundant in this case since you can store the user_id directly on the message table. A user can have many messages, ie. One-To-Many.