Laravel Eloquent 将许多Where(和)与Where(或)的小节链接起来

问题描述 投票:0回答:2

我正在尝试构建一个请求,该请求返回特定用户 ID 的子集(通过connected_id)的所有用户,这些用户也在一个或多个年龄范围之间(例如“20-30”、“50-60”) 。年龄范围列表通过另一个数组 ($ageRangeTable) 呈现。 ID 为 5 的用户将被忽略。

用户表仅包含出生日期,因此必须动态计算年龄。

这是我到目前为止所得到的,但导出的 SQL 忽略了 OR 部分。 (我现在使用“explode”来分隔最小和最大年龄,因为实际的字符串“x-y”可能很快就会更改为其他内容)。

 $ageRangeTable = ['20-30','50-60'];
 $result = Users::where('connected_id', Auth::user()->id)
        ->where('id' , '!=',  5)
        ->where(
            function ($query) use ($ageRangeTable) {
                $count = 0;
                foreach($ageRangeTable as $agerange){
                    list($min,$max) = explode( "-", $agerange);
                    if($count == 0){
                        $query->where(`TIMESTAMPDIFF( YEAR, 'dateofbirth', CURDATE() )`, `between`, `{$min} AND {$max}`);
                    }else{
                        $query->orWhere(`TIMESTAMPDIFF( YEAR, 'dateofbirth', CURDATE() )`, `between`, `{$min} AND {$max}`);
                    }
                    $count++;
                }
                return $query;
            }
        );
        //->get(); don't use this yet as we just want to review SQL for now...

        dd($result->toSql());

生成的 SQL 如下所示:

  "select * from `users` where `connected_id` = ? and (`id` != ?)"

...忽略所有“或”。我预料到了这个_

  "select * from `users` where `connected_id` = ? and (`id` != ?) and ((`TIMESTAMPDIFF( YEAR, 'dateofbirth', CURDATE() )` BETWEEN ? AND ?) OR (`TIMESTAMPDIFF( YEAR, 'dateofbirth', CURDATE() )` BETWEEN ? AND ?))

接下来我可以尝试什么?

mysql laravel eloquent
2个回答
1
投票

您这里有几个问题:

  • 反引号应放在列名称周围,引号应放在字符串周围
  • 单引号不会扩展最小和最大变量

您还可以使用一些小调整来更多地利用 QueryBuilder

  • 使用
    whereBetween
    进行查询
  • 使用
    DB::raw
    作为列

您的查询将如下所示:

$result = Users::where('connected_id', Auth::user()->id)
    ->where('id', '!=', 5)
    ->where(
        function($query) use ($ageRangeTable) {
            $count = 0;
            foreach($ageRangeTable as $agerange) {
                [$min, $max] = explode("-", $agerange);
                if($count == 0) {
                    $query->whereBetween(DB::raw('TIMESTAMPDIFF( YEAR, `dateofbirth`, CURDATE() )'), [$min, $max]);
                } else {
                    $query->orWhereBetween(DB::raw('TIMESTAMPDIFF( YEAR, `dateofbirth`, CURDATE() )'), [$min, $max]);
                }
                $count++;
            }
            return $query;
        }
    );

1
投票

尝试使用原始查询 -

whereRaw

$ageRangeTable = ['20-30', '50-60'];

$sqlRaw = [];

foreach ($ageRangeTable as $range) {
    [$min, $max] = explode( '-', $range);

    $sqlRaw[] = sprintf('YEAR(DATE_SUB(NOW(), INTERVAL TO_DAYS(dateofbirth) DAY)) BETWEEN %d AND %d', $min, $max);
}

$result = Users::query()
    ->where('connected_id', \Auth::user()->id)
    ->where('id' , '!=',  5)
    ->whereRaw(implode(' AND ', $sqlRaw))
    ->get();
© www.soinside.com 2019 - 2024. All rights reserved.