【问题标题】:How to join / union multiple results from same table?如何加入/联合来自同一张表的多个结果?
【发布时间】:2017-03-02 23:14:18
【问题描述】:

我的 mysql 表看起来像:

user_messages

标识 |用户 ID |电话号码 |留言 |方向 | created_at

用户

标识 |名字

我想将 user_messages 'group by' 两次,然后 UNION 结果。我为什么要这样做?因为 user_id 有时有一个有效的用户 id(除了'-1')然后我按它分组,如果它有 -1,然后按 phone_number 分组。

如果 user_id 设置为有效用户,我还想将结果与 users 表左连接以获取用户名

我几乎完成了查询,但问题是:
- 我希望结果具有来自 group by 的记录是最新的,这意味着最大的 created_at 值

select * from (
(
    select *, count(*) as `total` from
      (select `user_id`, `message`, `created_at`, `phone_number`,`direction` from `users_messages` where `user_id` != -1  order by `created_at` desc)
    as `t1` group by `user_id`
)
union
(
    select *, count(*) as `total` from
        (select `user_id`, `message`, `created_at`, `phone_number`,`direction`  from `users_messages` where `user_id` = -1 order by `created_at` desc)
    as `t2` group by `phone_number`
)
) as `t3`
left join (select `id`,`name` from `users`) as `t4` on `t3`.`user_id` = `t4`.`id` order by `created_at` desc

这让我得到的是未按 created_at DESC 排序的结果

更新: 该查询实际上在我的本地机器上有效,但在生产服务器上无效。在我的本地机器上我有 5.5.42 - Source distribution 和在服务器上 Ver 14.14 Distrib 5.7.17, for Linux (x86_64) using EditLine wrapper ... 有什么问题?

在本地机器上,它正确地返回了 max created_at,但在服务器上,它返回了为按记录分组而创建的 FIRST

【问题讨论】:

  • 您能否提供样本数据和样本数据的预期结果?我觉得这个查询可以简化很多。查看数据可以更好地理解问题。
  • SELECT *, COUNT(*) FROM .... GROUP BY [non-row-identity field] 很少是个好主意。
  • @JorgeCampos 它确实有效,但在远程服务器上给了我不同的结果。我已经更新了我的问题!

标签: mysql sql


【解决方案1】:

这样的事情应该可以工作:

SELECT s.`user_id`, um.`phone_number`, s.msgCount
   , um.`message`, um.`created_at`, um.`direction`
   , u.`name` AS userName
FROM (
    SELECT `user_id`, IF(`user_id` = -1, `phone_number`, '') AS altID, MAX(`created_at`) AS lastCreatedAt, COUNT(*) AS msgCount
    FROM `users_messages` 
    GROUP BY user_id, altID
) AS s
INNER JOIN `users_messages` AS um 
    ON s.user_id = um.user_id 
    AND s.altID = IF(um.`user_id` = -1, um.`phone_number`, '')
    AND s.lastCreatedAt = um.created_at
LEFT JOIN `users` AS u
    ON s.user_id = u.user_id
ORDER BY um.created_at DESC
;
  • s 子查询获取每个用户和无用户电话号码的摘要信息;计算的摘要信息包括最新的created_at 值,用于以下用途....
  • um 的联接获取最后一条消息的行数据(通过在联接条件中包含来自slastCreatedAt 值)
  • users 的最终连接用于获取已知用户的user.name(并假设没有-1 用户,或者这样的用户将具有适当的'unknown' 名称.)

【讨论】:

  • 这很有意义,但为什么我得到:'on Clause'中的未知列'u.user_id'
  • 像魅力一样工作!!!!!!!!!我刚刚将 u.user_id 编辑为 u.i​​d 你是最棒的!
【解决方案2】:

由于您是按 user_id 和 phone_number 分组的,因此您无法保留消息或方向。在每个子查询中为 created_at 添加一个 max 函数。我认为这会奏效。

select * from (
(
    select user_id
          ,'' as phone_number
          ,max('created_at') as 'created_at'
          ,count(*) as `total` from
      (select `user_id`
             ,`created_at`
       from `users_messages` 
       where `user_id` != -1)
    as `t1` group by `user_id`
)
union
(
    select '' as user_id
          ,phone_number
          ,max('created at') as 'created_at'
          ,count(*) as `total` from
        (select `created_at`
               ,`phone_number'
         from `users_messages` 
         where `user_id` = -1)
    as `t2` group by `phone_number`
)
) as `t3`
left join (select `id`,`name` from `users`) as `t4` 
on `t3`.`user_id` = `t4`.`id` 
order by `created_at` desc

【讨论】:

  • 我的查询确实有效,但在远程服务器上给了我不同的结果。我已经更新了我的问题!
猜你喜欢
  • 1970-01-01
  • 2019-04-20
  • 2010-11-17
  • 2018-02-26
  • 1970-01-01
  • 2017-09-28
  • 1970-01-01
  • 2017-09-28
  • 1970-01-01
相关资源
最近更新 更多