Select the Latest Message Between the communication of two user in mysql - mysql

I have a simple table maintaining messages between users. The table structure looks like
sender receiver message sendtime
1 2 m1 2012-01-01 12:12:12
2 1 m2 2012-01-01 12:50:20
1 2 m3 2012-01-01 12:55:55
1 3 m4 2012-01-02 05:05:05
1 4 m5 2012-01-05 05:20:20
4 1 m6 2012-01-06 06:05:00
4 1 m7 2012-01-07 11:11:11
2 4 m8 2012-01-08 05:01:01
Now, for the user with ID 1, I need the result like this
sender receiver message sendtime
1 2 m3 2012-01-01 12:55:55
1 3 m4 2012-01-02 05:05:05
4 1 m7 2012-01-07 11:11:11
That is I need the recent messages for the particular user whether he is sender or receiver.
Though, it seem easy, I cannot find a way to write a single mysql query.
Also, I want suggestion if for this kind of solution, my table design is poor.
Note: One thing, which I think I should mention is, for instance there are multiple communication between user 1 and user 2. I need the latest communication between them two whether user 1 is a sender or receiver, only the recent.
Most users are suggesting the query, that will bring one record with the sender 1, receiver 2 and then sender 2, receiver 1. I don't need these two record because this is a communication between same user 1 and user 2. I need one the latest one for the user specified with each of other users.
Thanks,

SELECT data.* FROM
(SELECT MAX(sendtime) AS sendtime
FROM data
WHERE 1 IN (sender,receiver)
GROUP BY IF (1 = sender,receiver,sender)) AS latest
LEFT JOIN data ON latest.sendtime = data.sendtime AND 1 IN (data.sender, data.receiver)
GROUP BY IF (1 = data.sender,data.receiver,data.sender)
I recommend to use unique sequence id in your table to avoid external GROUP BY.
If you have incrementing unique message_id (i.e. bigger message_id corresponds to later sendtime), the query would be much simpler:
SELECT data.* FROM
(SELECT MAX(message_id) AS message_id
FROM data
WHERE 1 IN (sender,receiver)
GROUP BY IF (1 = sender,receiver,sender)) AS latest
LEFT JOIN data USING(message_id)

Try making message as the primary key and put sender and receiver in 2 separate tables for the same message like this:
Table 1: {message, sender, sendtime}
Table 2: {message, receiver, sendtime}

Try this:
SELECT Distinct (*)
FROM tableName m
WHERE date =
(
SELECT MAX (date)
FROM tableName
)

To me it feels simpler to use an own ID based on the sender and receiver. No JOIN and just one GROUP BY needed:
SELECT sender, receiver, message, MAX(time)
FROM (
SELECT *,
CASE WHEN sender < receiver
THEN CONCAT(sender,'&', receiver)
ELSE CONCAT(receiver,'&', sender) END AS fromto
FROM data) AS a
GROUP BY fromto

I take 30 mins to find the solution for this problem because I have thew same problem
just take it simple
SELECT DISTINCT sent_by FROM messages WHERE sent_to = 1 UNION SELECT DISTINCT sent_to FROM messages WHERE sent_by = 1

This will work out
$query = "SELECT * FROM tableName WHERE `sender`='$userNumber' OR `receiver`='$userNumber' ORDER BY `sendtime` DESC LIMIT 0,1";

Related

Query items from a history table

I have a "library" history table (Excel like) to see where a book was or is.
id
date
book
action
client
1
2020-12-01
1
toClient
1
2
2020-12-02
1
returned
1
3
2020-12-03
1
toClient
2
4
2020-12-04
2
toClient
2
5
2020-12-05
3
toClient
1
6
2020-12-06
3
returned
1
7
2020-12-07
2
returned
2
8
2020-12-08
2
toClient
1
I am trying to discover how many books and what books are by client 2 (for example).
I have something like that to find everything about the books that are or was by client 2:
SELECT * FROM history WHERE book IN
(SELECT book FROM history WHERE action='toClient' AND client=2 GROUP BY book)
But so, I get also books that aren't anymore on client 2.
Is there a simple way to query items where the last action was "toClient" and not "returned" and the current client is client 2?
Edit: forgot to write that action can be also revision, timeExtension or something other.
To list books that are currently out, you can do:
select h.*
from history h
where
action = 'toClient'
and h.date = (select max(d1.date) from history h1 where h1.book = h.book)
The idea is to filter on the latest event date per book. Then we only retain the row if the corresponding event is "toClient".
This returns the results for all clients. If you want just one client, just add an additional condition to the where clause of the query:
and client = 2
You can also do this with window functions:
select *
from (
select h.*,
rank() over(partition by book order by date desc) rn
from history h
) h
where rn = 1 and action = 'toClient' -- and client = 2

how to get the latest record of loginevent from each user?

This question may already asked, but my question refers to two separate tables. I have only seen the answer when using same table with date row on it.
I have two tables, one is the user table and the other is login_log table.
I want to get the event from latest date record and from each user.
I have already made sql query, but cant understand how can I pick the max(date) from separate user.
SELECT s.username_id,s.date,s.event,m.username
FROM sys_log s join
users m
on s.username_id = m.id
id, username
---------
1 test
2 test2
id, username_id, date, event
------------------------------------------
1 1 1/1/2017 22:10:11 logout
2 1 1/1/2017 22:09:11 login
3 2 1/1/2017 21:05:11 logout
4 2 1/1/2017 21:02:11 login
the output should be like this
id, username, event ,date
-------------------------
1 test logout xxx
2 test2 logout xxx
Does this do what you want?
select s.username_id, s.date, s.event, m.username
from sys_log s join
users m
on s.sys_auth_id = m.id
where s.date = (select max(s2.date) from sys_log s2 where s2.sys_auth_id = s.sys_auth_id);

Having the number of line having a specifc ID without group by SQL

I have a 'billing' table which represent all instances of billings from my subscribers. A subscriber can have multiple billings.
I have a simple SQL request which is :
SELECT count(billing_id),subscriber_id
FROM billing
group by subscriber_id
As a result I have a list of all my subscribers with the number of billings they've made.
I want to have a list of all the billings no grouped by subscribers, but I want the result of the previous request appearing in each lines.
Example:
Result of my previous request:
sub_id nb_billings
1 3
2 2
What I want :
sub_id nb_billings
1 3
1 3
1 3
2 2
2 2
Thanks
I'd do it like this;
SELECT
b.subscriber_id
,a.billing_count
FROM billing b
JOIN (SELECT subscriber_id, count(billing_id) billing_count FROM billing GROUP BY subscriber_id) a
ON b.subscriber_id = a.subscriber_id
The subquery works out the count of billing_id by subscriber, this is then joined to all rows of your original table (using subscriber_id). This should give the result you're after.
You can use a subquery to do that:
SELECT
(SELECT count(t2.billing_id) FROM billing t2 WHERE t2.subscriber_id = t1.subscriber_id),
t1.subscriber_id
FROM billing t1
I guess this should suffice :
SELECT s.subscriber_id,
s.billing_id,
s.TotalCount
FROM (
SELECT subscriber_id,
billing_id,
COUNT(billing_id) AS TotalCount
FROM BILLING
GROUP BY subscriber_id,
billing_id
) s
GROUP BY s.subscriber_id,
s.TotalCount,
s.billing_id
ORDER BY s.subscriber_id
This should give you the result as follows :
subscriber_id billing_id TotalCount
1 10a 2
1 10b 2
1 10c 1
2 10a 1
2 10b 1
2 10c 3
2 10d 1
You can see this here -> http://rextester.com/AVVS23801
Hope this helps!!
select subscriber_id,count(billing_id)over(partition by subscriber_id)
from billing
will do just that.

Getting only one row per combination of two IDs [duplicate]

I have a simple table maintaining messages between users. The table structure looks like
sender receiver message sendtime
1 2 m1 2012-01-01 12:12:12
2 1 m2 2012-01-01 12:50:20
1 2 m3 2012-01-01 12:55:55
1 3 m4 2012-01-02 05:05:05
1 4 m5 2012-01-05 05:20:20
4 1 m6 2012-01-06 06:05:00
4 1 m7 2012-01-07 11:11:11
2 4 m8 2012-01-08 05:01:01
Now, for the user with ID 1, I need the result like this
sender receiver message sendtime
1 2 m3 2012-01-01 12:55:55
1 3 m4 2012-01-02 05:05:05
4 1 m7 2012-01-07 11:11:11
That is I need the recent messages for the particular user whether he is sender or receiver.
Though, it seem easy, I cannot find a way to write a single mysql query.
Also, I want suggestion if for this kind of solution, my table design is poor.
Note: One thing, which I think I should mention is, for instance there are multiple communication between user 1 and user 2. I need the latest communication between them two whether user 1 is a sender or receiver, only the recent.
Most users are suggesting the query, that will bring one record with the sender 1, receiver 2 and then sender 2, receiver 1. I don't need these two record because this is a communication between same user 1 and user 2. I need one the latest one for the user specified with each of other users.
Thanks,
SELECT data.* FROM
(SELECT MAX(sendtime) AS sendtime
FROM data
WHERE 1 IN (sender,receiver)
GROUP BY IF (1 = sender,receiver,sender)) AS latest
LEFT JOIN data ON latest.sendtime = data.sendtime AND 1 IN (data.sender, data.receiver)
GROUP BY IF (1 = data.sender,data.receiver,data.sender)
I recommend to use unique sequence id in your table to avoid external GROUP BY.
If you have incrementing unique message_id (i.e. bigger message_id corresponds to later sendtime), the query would be much simpler:
SELECT data.* FROM
(SELECT MAX(message_id) AS message_id
FROM data
WHERE 1 IN (sender,receiver)
GROUP BY IF (1 = sender,receiver,sender)) AS latest
LEFT JOIN data USING(message_id)
Try making message as the primary key and put sender and receiver in 2 separate tables for the same message like this:
Table 1: {message, sender, sendtime}
Table 2: {message, receiver, sendtime}
Try this:
SELECT Distinct (*)
FROM tableName m
WHERE date =
(
SELECT MAX (date)
FROM tableName
)
To me it feels simpler to use an own ID based on the sender and receiver. No JOIN and just one GROUP BY needed:
SELECT sender, receiver, message, MAX(time)
FROM (
SELECT *,
CASE WHEN sender < receiver
THEN CONCAT(sender,'&', receiver)
ELSE CONCAT(receiver,'&', sender) END AS fromto
FROM data) AS a
GROUP BY fromto
I take 30 mins to find the solution for this problem because I have thew same problem
just take it simple
SELECT DISTINCT sent_by FROM messages WHERE sent_to = 1 UNION SELECT DISTINCT sent_to FROM messages WHERE sent_by = 1
This will work out
$query = "SELECT * FROM tableName WHERE `sender`='$userNumber' OR `receiver`='$userNumber' ORDER BY `sendtime` DESC LIMIT 0,1";

Grouping notifications by type in MySql

I have the following table structure for notifications table.
id user_id post_id type status date seconduser_id
1 1 23 1 0 somedate 4
2 2 25 2 0 somedate 3
3 3 26 1 0 somedate 4
4 4 28 2 1 somedate 5
5 5 21 2 0 somedate 4
---
---
and so on
Here type = 1 means a like and type = 2 means a comment. status = 0 means seconduser_id hasn't seen the notification yet. seconduser_id is the notification recipient.
Is it possible to get notifications for 1 user (example seconduser_id = 4), with notification grouped by type, showing count and the latest user_id for each type (in one query)?
The implementation of this would be something like User3 and 10 other people liked your post.
Edit: So far I have something that pulls all notification for user 4 and then groups in php. I don't think this is efficient and so am looking for better solutions.
The basic answer is an aggregation query. The complication is getting the latest user id for each type. THere is one method, using substirng_index()/group_concat():
select type, count(*),
substring_index(group_concat(user_id order by id desc), ',', 1) as latest_user
from notifications n
where secondaryuser_id = 4 and status = 0
group by type;
I am not sure if you also want to filter by status.
Edit (added by OP):
Using the above code and grouping by both post_id and type. Because you want to say User1 and 10 others liked your post. Which means for each grouped notification, post_id has to be unique.
SELECT *, substring_index(group_concat(user_id order by id desc), ',', 1) as latest_user, COUNT(post_id) AS total
FROM notifications n
WHERE seconduser_id = 4 and status = 0
GROUP BY post_id, type
Try this:
SELECT MAX(user_id) AS LatestUser, type, COUNT(type) AS total
FROM notifications
WHERE seconduser_id = 4
GROUP BY type