我正在一个小仪表板中构建一个电子邮件收件箱。是使用其他 API 的自定义电子邮件客户端。我准备DB结构的方式如下:
传入
表
╔════╦════════════════════╦═══════════════════╦═════════════════════════════════════════╦══════════════════════╗
║ id ║ email_from ║ email_to ║ email_body ║ date ║
╠════╬════════════════════╬═══════════════════╬═════════════════════════════════════════╬══════════════════════╣
║ 1 ║ stack@overflow.com ║ mitch@example.com ║ Your question has a downvote for newbie ║ 2017-12-28T00:00:00Z ║
║ 2 ║ stack@exchange.com ║ mitch@example.com ║ You gotta learn SQL, buddy :/ ║ 2017-12-28T00:01:43Z ║
║ 3 ║ stack@overflow.com ║ mitch@example.com ║ Guess what? 42 ║ 2017-12-28T00:05:00Z ║
║ 3 ║ stack@overflow.com ║ mitch@example.com ║ This is a bot, stop responding ║ 2017-12-28T00:10:00Z ║
╚════╩════════════════════╩═══════════════════╩═════════════════════════════════════════╩══════════════════════╝
传出
表
╔════╦═══════════════════╦════════════════════╦════════════════════════════════════╦══════════════════════╗
║ id ║ email_from ║ email_to ║ email_body ║ date ║
╠════╬═══════════════════╬════════════════════╬════════════════════════════════════╬══════════════════════╣
║ 1 ║ mitch@example.com ║ stack@overflow.com ║ That is bad news ║ 2017-12-28T00:00:50Z ║
║ 2 ║ mitch@example.com ║ stack@exchange.com ║ I know :( ║ 2017-12-28T00:01:45Z ║
║ 3 ║ mitch@example.com ║ stack@overflow.com ║ Answer to the Ultimate Question... ║ 2017-12-28T00:07:42Z ║
╚════╩═══════════════════╩════════════════════╩════════════════════════════════════╩══════════════════════╝
所以,我想做一个像 Gmail 这样的小收件箱,您可以在其中看到所有电子邮件的列表,按电子邮件地址(或对话)分组并按日期排序,在顶部显示最新的,在每个对话中,显示仅该对话的最后一条消息。
我的查询尝试
SELECT `email_from` as `thread_email`, `email_body`, `date`
FROM (
SELECT `email_from`, `email_body`, `date` FROM `incoming`
UNION
SELECT `email_to` as `email_from`, `email_body`, `date` FROM `outgoing`
) AS t_union
GROUP BY `email_from`
ORDER BY `date` DESC
结果:
╔════════════════════╦═════════════════════════════════════════╦══════════════════════╗
║ thread_email ║ email_body ║ date ║
╠════════════════════╬═════════════════════════════════════════╬══════════════════════╣
║ stack@exchange.com ║ You gotta learn SQL, buddy :/ ║ 2017-12-28T00:01:43Z ║
║ stack@overflow.com ║ Your question has a downvote for newbie ║ 2017-12-28T00:00:00Z ║
╚════════════════════╩═════════════════════════════════════════╩══════════════════════╝
它仅显示来自 incoming
表的结果。
我的预期结果
- 按电子邮件地址分组,这代表一个对话(称为
thread_email
,基本上每个thread_email
一行) - 每一行(或 session ,或
thread_email
)仅显示该thread_email
的最新消息(最后一条消息可能是传入或传出) - 按日期排序(最近的在前)
╔════════════════════╦════════════════════════════════╦══════════════════════╗
║ thread_email ║ email_body ║ date ║
╠════════════════════╬════════════════════════════════╬══════════════════════╣
║ stack@overflow.com ║ This is a bot, stop responding ║ 2017-12-28T00:10:00Z ║
║ stack@exchange.com ║ I know :( ║ 2017-12-28T00:01:45Z ║
╚════════════════════╩════════════════════════════════╩══════════════════════╝
SQL fiddle :http://sqlfiddle.com/#!9/ed9642/4
这是实现这一目标的新手方法吗?对另一种数据库结构有什么建议,这种结构更简单但也更清晰有序?
最佳答案
正如 Gordon 所说,如果 group by
你的数据,将数据减少到一行,但如果你只使用 order by
子句,你仍然会得到重复的数据, 它将从联合表中获取所有数据。
group by
子句也有一个 having
子句,但它似乎只适用于数字,比如 count(*) > 2
和其他东西。
在PostgreSQL我们有一个叫做 array_agg
的东西,它将一些数据转换为数组,然后我们可以将其作为数组访问。
在 MySQL 中,我发现的唯一类似的是 group_concat将所有数据与相同的分组语句转换为字符串中用','连接的语句,所以,idk如果这解决了你的问题,但你可以尝试这个并在应用程序端处理结果,而不是在SQL端处理。
你可以这样使用:
select email_from, group_concat(email_body), date from (
select email_from, email_body, date from incoming union all
select email_to as email_from, email_body, date from outgoing
) as t_union group by email_from order by date desc;
或者,在最后一种情况下,以非优化方式执行:
select email_from, email_body, date from (
select email_from, email_body, date from incoming union all
select email_to as email_from, email_body, date from outgoing
) as t_union_1 where date in (
select max(date) from (
select email_from, email_body, date from incoming union all
select email_to as email_from, email_body, date from outgoing
) as t_union group by email_from order by date desc
);
关于php - 通过给定字段通过 UNION 组加入 2 个表,并仅获取该组的最新信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48000660/