【问题标题】:SQL Subquery JOIN issue with Laravel Query BuilderLaravel 查询生成器的 SQL 子查询 JOIN 问题
【发布时间】:2021-01-10 13:02:54
【问题描述】:

我想我一直在理解 Laravel 查询生成器和纯 SQL 之间的融合。

我有 2 张桌子:

  • 用户:包含主键为user_id的用户
  • User_Action :这是一个表,其中包含由动作的user_iddatetime 组成的主键组成的记录。

例如:

用户

user_id
1

user_action

user_id    datetime              action_type
1          2017-12-01 12:10:00   y
1          2017-12-01 12:00:00   x

我的需要

现在我想检索一个用户列表,其中包含每个用户的最新操作。所以我只需要在 JOIN 中从useruser_action 获取 1 行,并且这一行必须是最新日期时间的行。 所以在我的前任;我只想使用 LEFT JOIN 获取日期时间为 2017-12-01 12:10:00 的记录(即使没有操作也可以检索用户)。

我尝试了以下方法:

$userActionSubquery = DB::table('user_action')
        ->select()
        ->orderBy('datetime', 'DESC')
        ->limit(1);
$query->leftJoinSub($userActionSubquery, 'user_action', function ($join) {
         $join->on('user_action.user_id', '=', 'user.user_id');
})->groupBy('user_id');

这样做,我没有从user_action 表中得到任何东西,但是如果给定用户的操作是表中最新的,它就可以工作! 我认为$join->on 会过滤用户ID,但是JOIN 子查询在没有这个过滤器的情况下运行,我只能在子查询中使用WHERE,因为我没有user_id 可以提供!这是一个获取用户列表的查询!

PS : 生成的查询是

SELECT user.user_id FROM user left join (SELECT * FROM user_action ORDER BY datetime DESC LIMIT 1) as user_action on user_action.user_id = user.user_id WHERE user.tenant_id in ('7') GROUP BY `user_id`

我错过了一些成功的东西,谢谢你的帮助!

【问题讨论】:

    标签: sql laravel join


    【解决方案1】:

    试试这个:

    $sub = \DB::table('user_action')
        ->select([
            'user_id',
            \DB::raw('SUBSTRING_INDEX( GROUP_CONCAT( action_type ORDER BY datetime DESC ), ",", 1 ) AS last_action_type')
        ])
        ->groupBy('user_id');
    
    $data = \DB::table('user')
        ->leftJoinSub($sub, 'tmp', function ($join) {
            $join->on('tmp.user_id', '=', 'user.id');
        })->get();
    

    sql:

    SELECT * FROM user LEFT JOIN ( SELECT user_id, SUBSTRING_INDEX( GROUP_CONCAT( action_type ORDER BY datetime DESC ), ',', 1 ) AS last_action_type FROM user_action GROUP BY user_id ) AS tmp ON tmp.user_id = user.id
    

    它适用于我的测试环境:

    用户

    id   name
    1    john
    2    jack
    

    user_action

    id   user_id   datetime              action_type
    1    1         2020-09-24 23:51:00   login
    2    1         2020-09-24 23:51:20   search
    3    2         2020-09-24 23:30:00   login
    4    2         2020-09-25 00:00:00   coding
    

    结果

    Illuminate\Support\Collection Object
    (
        [items:protected] => Array
            (
                [0] => stdClass Object
                    (
                        [id] => 1
                        [name] => john
                        [user_id] => 1
                        [last_action_type] => search
                    )
    
                [1] => stdClass Object
                    (
                        [id] => 2
                        [name] => jack
                        [user_id] => 2
                        [last_action_type] => coding
                    )
    
            )
    
    )
    

    【讨论】:

    • 谢谢,让我完全理解我在做什么的关键是在子查询中使用聚合函数。我不知道我当时为什么这么迷茫!
    • 我做了和你类似的事情,但我使用了宁愿选择链接语法和 MAX 聚合函数:$query->select('user_id')->selectRaw('MAX(datetime) as maxDatetime')->groupBy('user_id')
    猜你喜欢
    • 2018-12-30
    • 1970-01-01
    • 2013-06-28
    • 2018-11-16
    • 1970-01-01
    • 2019-03-29
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    相关资源
    最近更新 更多