【问题标题】:Ordering results based on related table with laravel query builder使用 laravel 查询构建器基于相关表排序结果
【发布时间】:2018-07-29 12:57:54
【问题描述】:

我有两个模型/表:用户和帖子。一个用户可以有很多帖子,每个帖子属于一个用户。

我正在尝试根据用户最近的帖子创建时间长短按升序返回用户列表。

例如

users:
id    |    name    | 
--------------------
1     |   user 1   | 
2     |   user 2   | 
3     |   user 3   | 

posts:
id    |    user_id  |       created_at      |    
---------------------------------------------
1     |      1      |    2018-02-19 08:00   |  
2     |      2      |    2018-02-19 09:00   |
3     |      3      |    2018-02-19 10:00   |
4     |      1      |    2018-02-19 11:00   |  
5     |      1      |    2018-02-19 12:00   |
6     |      2      |    2018-02-19 13:00   |

我希望能够返回以下结果

[
    {
        id: 3,
        name: "user 3"
    },
    {
        id: 1,
        name: "user 1"
    },
    {
        id: 2,
        name: "user 2"
    }
]

由于用户 3 的最新帖子创建时间最长,其次是用户 1,然后是用户 2。

到目前为止,我已经尝试过了,但它为用户返回了重复的结果:

    return $this->builder
                ->join('posts', function ($join) {
                    $join->on('users.id', '=', 'posts.user_id')
                         ->orderBy('posts.created_at', 'desc')
                         ->limit(1);
                })
                ->orderBy('posts.created_at', 'asc')
                ->get();

我也试过这个,它没有返回任何重复的结果,但排序错误:

    return $this->builder
                ->join('posts', 'users.id', '=', 'posts.user_id')
                ->groupBy('users.id')
                ->take(1)
                ->orderBy('posts.created_at', 'asc')
                ->get();

我觉得这是我所追求的两者的某种组合,但我无法解决。任何帮助将不胜感激,非常感谢。我正在使用 Laravel 5.4

【问题讨论】:

  • return $this->builder->join('posts', 'users.id', '=', 'posts.user_id')->orderBy('posts.created_at', 'desc')->groupBy('users.id')->get() 的输出是什么?
  • 嗨 @linktoahref 该查询按 3、2、1 的顺序返回用户
  • 如果你这样做groupBy('posts.user_id') 会怎样?
  • 相同的结果:3、2、1

标签: mysql sql database laravel join


【解决方案1】:

这是一个原始的 MySQL 查询,应该可以解决问题:

SELECT
    t1.id, t1.name
FROM users t1
LEFT JOIN
(
    SELECT user_id, MAX(created_at) AS created_at
    FROM posts
    GROUP BY user_id
) t2
    ON t1.id = t2.user_id
ORDER BY
    t2.created_at;

这是我对相应 Laravel 查询的尝试:

DB::table('users')
    ->select('id', 'name')
    ->join(DB::raw('(SELECT user_id, MAX(created_at) AS created_at
                    FROM posts GROUP BY user_id) t'),
    function($join)
    {
       $join->on('users.id', '=', 't.user_id');
    })
    ->orderBy('t.created_at', 'ASC')
    ->get();

【讨论】:

  • 这行得通!只需将代码从 DESC 稍微调整为 ASC,因为我们根据最新的帖子从旧到新对用户进行排序。我已经编辑了答案
  • @dbatten 感谢您解释订单更改背后的原因。这是有道理的,很高兴我能帮助你。
【解决方案2】:

我知道这不是你想要的,但你可以这样

Post::with('user')->orderBy('created_at', 'DESC')->distinct()->get(['user_id']);

它会给你这个

array:3 [▼
  0 => array:2 [▼
    "user_id" => 1
    "user" => array:13 [▶]
  ]
  1 => array:2 [▼
    "user_id" => 2
    "user" => array:13 [▶]
  ]
  2 => array:2 [▼
    "user_id" => 3
    "user" => array:13 [▶]
  ]
]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-27
    • 2022-01-13
    • 2020-06-25
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多