如何在 Laravel 7 中使用原始 SQL 查询创建范围?

Posted

技术标签:

【中文标题】如何在 Laravel 7 中使用原始 SQL 查询创建范围?【英文标题】:How to make a scope with a raw SQL query in Laravel 7? 【发布时间】:2021-07-09 22:15:41 【问题描述】:

问题

我正在尝试使用此 SQL 查询 在我的 模型 中创建一个 范围

SELECT *
FROM ro_container_events
WHERE (container_id, location_timestamp, id)
IN (
    SELECT distinct container_id, MAX(location_timestamp) AS lts, MAX(id) AS rce_id
    FROM ro_container_events
    GROUP BY container_id
)

模型名称是 ContainerEvent,我的数据库中的表名称是 ro_container_events

另外,我知道 SQL 查询是有效的,因为我在我的 mysql 管理工具 (HeidiSQL) 中运行了它,它返回了正确的行。

我尝试过的

我的范围(在我的 ContainerEvent 模型中)当前如下所示:

public function scopeLatestEventForContainers($query)
    
       return $query->select(DB::raw('
            SELECT *
            FROM ro_container_events
            WHERE (container_id, location_timestamp, id)
            IN (
                SELECT distinct container_id, MAX(location_timestamp) AS lts, MAX(id) AS rce_id
                FROM ro_container_events
                GROUP BY container_id
            )'
       )
       );
    

但它不返回任何行?

我的研究

我一直在搜索这个主题,但似乎找不到我的范围有什么问题......

Laravel 文档说我们可以使用:

DB::raw('...')

为了进行特定的 SQL 查询。

而且我在其他一些线程上看到我应该能够使用以下内容创建范围:

return $query->select(DB::raw('...');

【问题讨论】:

你试过 print_r() 你把 print_r 里面的函数返回什么? 【参考方案1】:

我只是使用 Laravel 查询构建器尝试您的 SQL 语法,使用方法 toSql() 的结果返回您需要的确切内容。

SELECT * FROM ro_container_events WHERE (container_id, location_timestamp, id) IN (
    SELECT distinct container_id, MAX(location_timestamp) AS lts, MAX(id) AS rce_id
    FROM ro_container_events
    GROUP BY container_id
)

试试这个功能:

public function scopeLatestEventForContainers($query)

    return $query->whereIn(\DB::raw('(container_id, location_timestamp, id)'), function ($q) 
        $q->distinct()->select(\DB::raw('
            container_id,
            MAX(location_timestamp) AS lts,
            MAX(id) AS rce_id FROM `ro_container_events`
        '))->groupBy('container_id');
    );

希望对你有帮助:)

最好, vreedom18

【讨论】:

【参考方案2】:

试试 Eloquent:

//as your where in select this must return just one row with 3 field
$in =  ContainerEvent::distinct('container_id', 'location_timestamp', 'id')->where(fn($q) => 
   'id' => ContainerEvent::max('id')
   'location_timestamp' => ContainerEvent::max('location_timestamp')
])->get();

但这可能是错误的,因为 db 结构中存在野心。

【讨论】:

你能给我ContainerEvent的结果吗::get(container_id, max(location_timestamp), max(id)) ->distinct(); ? 它没有给出任何结果。如果我错了,请纠正我,但你不能给 get() 提供 3 个参数...? 试试我的项目这种情况。这不是最好的,但肯定会做你需要的。答案已更新。

以上是关于如何在 Laravel 7 中使用原始 SQL 查询创建范围?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Laravel 6 中转换原始 sql 查询?

如何在原始 sql WHERE IN [LUMEN/LARAVEL] 中绑定命名参数

Laravel 查询构建器 - 如何按别名分组,或进行原始 groupBy

在 Laravel 4 中转义原始 SQL 查询

Laravel 5 Eloquent:如何获取正在执行的原始 sql? (带有绑定数据)

如何在Rails 4中清理原始SQL