I'm writing a basic message-script in PHP/MySQL but I'm stuck at a database query right now. I'll appreciate any hints or assistance (:
I'm using two tables, since a message can be sent to several users:
messages:
id | sender_id | subject | ...
message_receivers:
message_id | receiver_id | ...
What I want to do now is display a message to the user that he selects. But I want to show the whole message history the user had in that conversation (jumping in browser to the one he selected). Doing this with a join is quite simple:
SELECT * FROM messages
JOIN message_receivers
ON messages.id = message_receivers.message_id
WHERE sender_id = x
AND receiver_id = y
But now I'm missing the information of other receivers of a message! And I have no clue how to get this information. Any ideas for that? (:
Join the message_receivers table one more time to retrieve the other recipients of the message:
SELECT
m.id, m.sender_id, m.subject,
r.receiver_id AS recipient,
c.receiver_id AS carboncopy
FROM messages AS m
INNER JOIN message_receivers AS r
ON m.id = r.message_id
LEFT OUTER JOIN message_receivers AS c
ON r.message_id = c.message_id AND r.receiver_id != c.receiver_id
WHERE m.sender_id = x AND r.receiver_id = y
The recipient that your are interested in will be in column recipient (in every result record). Other recipients will be in column carboncopy (one per result record). If carboncopy is NULL, then the message had only a single receiver.
If you want to see all the receivers of a message then remove the second part of the were clause:
AND receiver_id = y
at the same time you will want to specify the message_id because this will be to confusing to the user on the front end
AND message_id = z
You're missing information about other receivers of the message because of the clasue:
AND
receiver_id = y
This restricts the result set to just receiver y. Remove the clause, and you'll get them all. However you'll probably get every message sent where sender_id = x as well, so you'll need to limit the query by specifying a message_id.
So your final query should look something like this:
SELECT
*
FROM
messages
JOIN message_receivers ON messages.id = message_receivers.message_id
WHERE
sender_id = x
AND
message_id = y
you don't need to restrict your result to receiver_id = y, do you?
Also you might write the statement in a different way and easily return receivers ids:
SELECT m.*, r.receiver_id
FROM messages m, message_receivers r
WHERE m.id = r.message_id
AND m.sender_id = x
Related
thank you all for taking the time to read and help if you can! I have a query below that is getting large and messy, I was hoping someone could point me in the right direction as I am still a beginner.
SELECT
DATE(s.created_time_stamp) AS Date,
s.security_profile_id AS Name,
COUNT(*) AS logins,
CASE
WHEN COUNT(s.security_profile_id) <= 1
THEN '1'
WHEN COUNT(s.security_profile_id) BETWEEN 2 AND 3
THEN '2-3'
ELSE '4+'
END AS sessions_summary
FROM session AS s
INNER JOIN member AS m
ON s.security_profile_id = m.security_profile_id
JOIN member_entitlement AS me ON m.id = me.member_id
JOIN member_package AS mp ON me.id = mp.member_entitlement_id
**JOIN member_channels AS mc ON mc.member_id = m.id**
where member_status = 'ACTIVE'
and metrix_exempt = 0
and m.created_time_stamp >= STR_TO_DATE('03/08/2022', '%m/%d/%Y')
and display_name not like 'john%doe%'
and email not like '%#aeturnum.com'
and email not like '%#trendertag.com'
and email not like '%#sargentlabs.com'
and member_email_status = 'ACTIVE'
and mp.package_id = 'ca972458-bc43-4822-a311-2d18bad2be96'
and display_name IS NOT NULL
and s.security_profile_id IS NOT NULL
**and mc.id IS NOT NULL**
GROUP BY
DATE(created_time_stamp),
Name
ORDER BY
DATE(created_time_stamp),
Name
The two parts of the query with asterisks are the two most recently added clauses and they skew the data. Without these, the query runs fine. I am trying get a session summary which works fine, but I only want the sessions of people who have a 'channel' created. Maybe mc.id IS NOT NULL is not the way to do this. I will share my query that shows me how many people have created channels. Essentially, I am trying to combine these two queries in the cleanest way possible. Any advice is greatly appreciated!
-- Users that have Topic Channels and Finished Set Up FOR TRIAL DASH**
select count(distinct(m.id)) AS created_topic_channel
from member m right join member_channels mc on mc.member_id = m.id
left join channels c on c.id = mc.channels_id
JOIN member_entitlement AS me ON m.id = me.member_id
JOIN member_package AS mp ON me.id = mp.member_entitlement_id
where title not like '# Mentions'
and member_status = 'ACTIVE'
and metrix_exempt = 0
and m.created_time_stamp >= STR_TO_DATE('03/08/2022', '%m/%d/%Y')
and display_name not like 'john%doe%'
and email not like '%#aeturnum.com'
and email not like '%#trendertag.com'
and email not like '%#sargentlabs.com'
and member_email_status = 'ACTIVE'
and display_name IS NOT NULL
and mp.package_id = 'ca972458-bc43-4822-a311-2d18bad2be96';
The metric I am trying to retrieve from the DB is how many users have created a channel and logged in at least twice. Thank you again and have a wonderful day!!
If id is the primary key of member_channels then it does not make sense to check if it is null.
If all you want is to check whether a member has a 'channel' created, then instead of the additional join to member_channels, which may cause the query to return more rows than expected, you could use EXISTS in the WHERE clause:
where member_status = 'ACTIVE'
and .......................
and EXISTS (SELECT 1 FROM member_channels AS mc WHERE mc.member_id = m.id)
I would guess your tables aren't at the same level of granularity. A member may have many sessions, and 0-many channels.
eg if member 123 has five sessions and creates three channels => 15 rows of data in this join.
To adjust for this, it's best practice to join on the same level of granularity. You could roll up sessions to the member level, channels to the member level, and then join both against members.
I have all day trying to get a result of a SQL query but does not give me the expected result.
My tables at which I consult are:
tcc_friends
id(PK AUTO_INCREMENT)
user_from (FK tcc_user (nickname) )
user_to (FK tcc_user (nickname) )
tcc_messages
id (PK AUTO_INCREMENT)
message
reg_time
wasRead
id_room (FK tcc_friends(id))
test records that have currently inserted are:
tcc_friends
id_room user_from user_to
5 hu example#gmail.com
6 hu example222222#hotmail.com
tcc_messages
id message id_room
1 a 5
2 b 5
3 c 3
SQL:
select
u.*,
f.id_room,COUNT(m.id) as newMessages
from
tcc_friends f,
tcc_user u,
tcc_messages m
where
u.nickname = 'hu' IN (u.nickname = f.user_from and f.user_to='hu') or
(u.nickname = f.user_to and f.user_from='hu') AND
(m.id_room = f.id_room and m.wasRead = 0)
GROUP BY
u.nickname;
RESULT:
id nickname id_room newMessages
81 example#gmail.com 5 2
I'm trying to get a user's friends and also add unread messages but displays only friends who have a message and I'd like to show all friends whether or not unread
Can anybody help me? Regards and Thank you all
First, don't use SELECT *. It's a horrible practice and you should get out of the habit of doing it as quickly as possible.
Second, learn how to use explicit JOINs. Don't list all of your tables in the WHERE clause. That's syntax that has been obsolete (for good reason) for 20 years. That's also what's causing your problem here because all of your joins are INNER JOINs by default.
Try something like this instead:
SELECT
U.id,
U.nickname,
F.id_room,
COUNT(M.id) as newMessages
FROM
tcc_Friends F
INNER JOIN tcc_User U ON U.nickname = F.user_from
LEFT OUTER JOIN tcc_Messages M ON
M.id_room = F.id_room AND
M.wasRead = 0 -- Are you using camelcase or underscores in column names?? Make up your mind and stick to it.
WHERE
F.user_to = 'hu'
GROUP BY
U.nickname;
That isn't going to get you all the way there, because I'm unclear on what exactly you're trying to get as far as number of unread messages - is it unread messages for the user at all? How does example#gmail.com have 2?
Remove the and m.wasRead = 0 from m.id_room = f.id_room and m.wasRead = 0 in the WHERE clause. By this query you get friends only with messages that have wasRead property 0. By doing above change you will get all the friends and 0 as the count if they don't have any new messages.
I have two tables for notification and one table for friend_list. One notification tbale is that has the notification info who created and type and all and second which marks which friend has read the notification. the was able to retrieve the notification created by the user to be displayed only to user's friend. But now I want from the second table named notification read to display notification which are unread to the user's friend.
The query I made is (from notification + friend_list table)
$sql3=mysql_query("select n.*,f.friend_id,f.uid,f.status from notification n,friend_list f where f.uid='$id' and f.status='1' and n.title_text='Global Notification' and n.user_id in ('$id' , f.friend_id) and n.owner_user_id=f.friend_id order by n.time_stamp desc");
now how to get notification unread by friend?
The second table is
uid (friend_id)
notification_id
is_read
now I want a query with my existing query to get notifications unread by friends.
try this:
SELECT n.*,f.friend_id,f.uid,f.status
FROM notification n
INNER JOIN friend_list f
ON n.owner_user_id = f.friend_id
INNER JOIN second_table s
ON f.friend_id = s.uid AND
n.notification_id = s.notification_id
WHERE f.uid='$id' AND
f.status='1' AND
n.title_text='Global Notification' AND
n.user_id IN ('$id' , f.friend_id) AND
s.is_read = 0
ORDER BY n.time_stamp DESC;
Let's supose that:
'$id' is the id of user that raise notification
n.user_id is user that raises notification
n.owner_user_id is user that receive notification
The query is:
select
n.*,f.friend_id,f.uid,f.status
from
notification n
inner join
friend_list f
on n.owner_user_id=f.friend_id
inner join
notification_read nr
on nr.notification_id = n.notification_id and
nr.uid = f.friend_id
where
f.status='1' and
n.title_text='Global Notification' and
n.user_id = '$id' and
nr.is_read = 0
order by n.time_stamp desc
Edited due new OP comment.
I've two tables in Mysql.
message -> msg_id(pk) and message(varchar)
track_record -> tr_id(pk), msg_id (foreign key), object_id (to whom the message is sent), profile_id(who sent the message)
Now i want to create a single query which gives me the messages and the sender profile id given the object_id.
E.g say i have the object_id 1.
Now i want to see all the message sent to the user with id 1.
Edited the answer to add my query which i tried
SELECT m.message, u.profile_profile_id FROm `message` as m, `user_track_record` as u
WHERE msg_id IN
(SELECT message_msg_id FROM user_track_record WHERE object_profile_id = 1)
and u.profile_profile_id IN
(SELECT profile_profile_id from `user_track_record` WHERE object_profile_id = 1)
Want to do this in both SQL and HQL.
Any help appreciated. Thanks
Your SQL query is much too complex.
Start with simple things:
Select all the track_records sent to user 1:
select tr.* from track_record tr where tr.object_id = 1
Now you would like the message linked to the track record. This is done using a join:
select tr.*, m.* from track_record tr
inner join message m on m.msg_id = tr.msg_id
where tr.object_id = 1
Now you would like only the ID of the sender, and the body of the message:
select tr.profile_id, m.message
from track_record tr
inner join message m on m.msg_id = tr.msg_id
where tr.object_id = 1
In HQL, the query is almost identical. You have a Message entity and a TrackRecord entity. TrackRecord has a ManyToOne association with Message. It also has a ManyToOne association with the sender and the receiver
select tr.sender.id, m.message
from TrackRecord tr
inner join tr.message m
where tr.receiver.id = 1
In my thread based messaging system, the table schema is
> messages table
id(int auto incr primary key)
body(varchar)
time(datetime)
>message_reference table
id(int auto incr primary key)
message_id(forgain key from message table)
sender
receiver
Here, I want to select the first message id which is sent to a new receiver and sender is the user who is logged in.
Doing this with multiple queries and some code is obviously possible but can it be done with a single query for performance issues??
You can try
EDIT:
If the id is auto increment, then the id will also increase with time and you can use:
SELECT message_reference.message_id, message_reference.receiver, messages.body
FROM message_reference, messages
WHERE message_reference.message_id IN (SELECT MIN(message_reference.message_id)
FROM message_reference
GROUP BY message_reference.receiver)
AND message_reference.message_id = messages.id AND message_reference.sender = <sender>
Here's my best guess as to what you want, but it would be easier if you gave known inputs, example data, and expected output.
SELECT
MR2.message_id
FROM (
SELECT
MR.sender,
MR.receiver,
M.MIN(`time`) AS min_time
FROM
Message_References MR -- Either use plural names (my personal preference) or singular, but don't mix them
INNER JOIN Messages M ON
M.id = MR.message_id
WHERE
MR.sender = <sender>
GROUP BY
MR.received) SQ
INNER JOIN Message_References MR2 ON
MR2.sender = SQ.sender AND
MR2.receiver = SQ.receiver AND
MR2.`time` = SQ.min_time
select mr.message_id from
message_reference as mr inner join
(select mr1.reciever max(m1.time) as time from messages as m1
inner join message_reference as mr1 on mr1.message_id = m1.id
group by mr1.reciever) as last
on mr.reciever = last.reciever and mr.time = last.time
join message reference with "maxtime per reciever" table on reciever and time
Well I got the answer, Just a group by query worked the way I wanted. I used query
SELECT SENDER,
RECEIVER,
BODY,
TIME,
MESSAGE_ID
FROM MESSAGE_REF JOIN MESSAGE
ON MESSAGE.ID=MESSAGE_REF.MESSAGE_ID
ORDER BY 'TIME' GROUP BY RECEIVER`
Thanks everyone for the help.