问题
See this table. It contains a chat log with incoming and outgoing messages
id | to_number | from_number |message | direction| type | generated_time
1 | +15005550004 | +16232950692 |Hai | OUTGOING | | 2019-07-12 15:13:00
2 | +16232950692 | +15005550004 |Hello | INCOMING | REVIEW | 2019-07-13 18:13:00
3 | +15005550004 | +16232950692 |How are you ? | OUTGOING | | 2019-07-13 21:15:00
4 | +15005550001 | +16232950692 |Good morning | OUTGOING | | 2019-07-12 12:13:00
5 | +16232950692 | +15005550001 |Have a nice day | INCOMING | REVIEW | 2019-07-12 12:17:00
6 | +15005550007 | +16232950692 |Hey John | OUTGOING | | 2019-07-12 14:13:00
Now i want to get the last generated message in each threads in which we got an incoming message with type REVIEW. See the desired output
to_number | from_number |message | direction| type | generated_time
+15005550004 | +16232950692 |How are you ? | OUTGOING | | 2019-07-13 21:15:00
+16232950692 | +15005550001 |Have a nice day | INCOMING | REVIEW | 2019-07-12 12:17:00
I tried a query
select *
from (select b.*
from (select *
from message m
where m.id in (select min(msg.id)
from message msg
where msg.direction = 'INCOMING'
group by msg.from_number, msg.to_number)
and m.type = 'REVIEW') a
left join (select * from message m) b
on ((a.from_number = b.to_number and a.to_number = b.from_number) or
(a.from_number = b.from_number and a.to_number = b.to_number))
order by b.generated_time desc
) c group by from_number,to_number order by generated_time desc;
But it is not grouping the messages properly. Can anybody help me to find a solution for this ?
回答1:
One way to determine the "thread" for each row is CONCAT() the LEAST of the two numbers with the GREATEST of the same two numbers.
We can then GROUP BY
on the "thread", to get the latest generated_time
. In HAVING
clause, we filter out only those "thread", which has atleast one 'INCOMING'
message with 'REVIEW'
type.
View on DB Fiddle
SELECT m1.*
FROM message AS m1
JOIN (SELECT Concat(Least(m.from_number, m.to_number), '|',
Greatest(m.from_number,
m.to_number))
AS
thread,
Max(m.generated_time)
AS max_generated_time
FROM message AS m
GROUP BY thread
HAVING Sum(m.direction = 'INCOMING'
AND m.type = 'REVIEW')) AS dt
ON dt.thread = Concat(Least(m1.from_number, m1.to_number), '|',
Greatest(m1.from_number, m1.to_number))
AND dt.max_generated_time = m1.generated_time;
Result
| id | to_number | from_number | message | direction | type | generated_time |
| --- | ------------ | ------------ | --------------- | --------- | ------ | ------------------- |
| 3 | +15005550004 | +16232950692 | How are you ? | OUTGOING | | 2019-07-13 21:15:00 |
| 5 | +16232950692 | +15005550001 | Have a nice day | INCOMING | REVIEW | 2019-07-12 12:17:00 |
Sidenote:
- Above approach (and your current schema design) is not able to use indexes, and hence it will not be performant.
- I would rather redesign the schema by creating two additional Master tables. One Master table would be storing the phone numbers:
phone_id
, andnumber
- Another Master table would be storing the "Thread", which will contain the
phone_id
values andthread_id
. You can then use thisthread_id
in yourmessage
table, instead of storing the phone numbers.
来源:https://stackoverflow.com/questions/57033530/mysql-group-by-with-2-columns-when-values-are-interchanged-in-columns