php - 通过给定字段通过 UNION 组加入 2 个表,并仅获取该组的最新信息

标签 php mysql sql

我正在一个小仪表板中构建一个电子邮件收件箱。是使用其他 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/

相关文章:

mysql - mysql和oracle的insert语句

MySQL 在一个查询中同时选择 SUM 和同一列的一个特定行 - 最佳方式?

mysql - Sql 查询,未使用 CURDATE() 函数检索正确的值

sql - 如何更改 MSSQL 中所有表、 View 和存储过程的架构

php - 如何从表单中获取表名值并将数据插入表中?

PHP 套接字 I/O 方法

php - Zend - 获取基本 Url 之后的所有内容( Controller 、操作和任何参数)

php - 没有从 volley stringRequest 获取 JSON POST 值

mysql - SQL:在groupby数据中查找前n个

php - 在 WordPress 主题中的图标上使用 CSS 的问题。