对 Laravel 查询构建器的 SQL 查询

Posted

技术标签:

【中文标题】对 Laravel 查询构建器的 SQL 查询【英文标题】:SQL query to Laravel query builder 【发布时间】:2020-02-06 19:28:19 【问题描述】:

我有两张桌子

risks

risk_id    name    area_id
1          a       1
2          b       1

risk_areas

id         name    parent_id
1          a       0
2          b       1
3          c       1
4          d       2

这是我的 sql 查询:

SELECT * FROM `risks` WHERE (`register_id` = 29 AND `area_id` = 1) 
OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id = 1) AND `register_id` = 29 ) 
OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id IN (SELECT id FROM risk_areas WHERE parent_id = 1)) AND `register_id` = 29 ) 

phpMyAdmin 中运行时,查询按预期工作。

我一直在尝试使用查询构建器将它实现到 Laravel 中。它从某个寄存器中获取风险(我以 29 为例)并找到其所有子风险(最多只能有 3 代,例如 parent->child->child)

我最初尝试过这个:

$query-> raw("
    SELECT * FROM `risks` WHERE (`register_id` = " . $q['register_id'] . "  AND `area_id` = ".$q['area_id'].") 
    OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id = ".$q['area_id'].") AND `register_id` = " . $q['register_id'] . " ) 
    OR (`area_id` IN (SELECT id FROM risk_areas WHERE parent_id IN (SELECT id FROM risk_areas WHERE parent_id = ".$q['area_id'].")) AND `register_id` =  " . $q['register_id'] . " ) 
");

$q['register_id'] 获取register_id$q['area_id'] 正确获取area_id

由于这不起作用(它只是输出了父母,甚至输出了具有相同 area_id 但注册 ID 不同的父母)我尝试了这个:

$query
    ->where('area_id', $q['area_id'])
    ->orWhere('area_id','IN',  function ($query) use($q) 
        $query->where('parent_id',$q['area_id'])
            ->where('register_id',$q['register_id']);
    )
    ->orWhere('area_id','IN',  function ($query) use($q) 
        $query->where('parent_id','IN', function ($query) use($q) 
            $query->where('parent_id',$q['area_id']);
        )
        ->where('register_id',$q['register_id']);
    )
    ->where('register_id',$q['register_id']);

但这与第一个相同。我的第三次尝试:

$query
    ->where('area_id', $q['area_id'])
    ->orWhere('area_id','IN',  function ($query) use($q) 
        $query->DB::table('risk_areas')
            ->select(DB::raw('id'))
            ->where('parent_id',$q['area_id'])
            ->where('register_id',$q['register_id']);
    )
    ->orWhere('area_id','IN',  function ($query) use($q) 
        $query->DB::table('risk_areas')
            ->select(DB::raw('id'))
            ->where('parent_id','IN', function ($query) use($q) 
                $query->DB::table('risk_areas')
                    ->select(DB::raw('id'))
                    ->where('parent_id',$q['area_id']);
            )
            ->where('register_id',$q['register_id']);
    )
    ->where('register_id',$q['register_id'])->get();

但这与第一个相同。如何复制 sql 查询?

编辑:

每个寄存器都有自己的 register_id(这仅用于加强搜索)。

每个登记册都包含许多风险。

每个风险只能有一个 risk_area。

无论是提供原始 sql 查询还是使用查询生成器,我每次都得到相同的结果。

我得到不同(和正确)结果的唯一一次是当我将查询输入 phpmyadmin 时(因此我想在我的代码中复制工作查询)。

正如我使用 dd() 检查过的,所有变量都有正确的值。

我认为原因是我在查询构建器上的语法不正确,这就是为什么我问如何将我的 sql 查询转换为 laravel 查询构建器。

编辑 2:

原始查询输出特定登记册的所有风险(显示的所有风险都属于该登记册)。当我将值硬编码到原始查询中时,我得到相同的结果(无论我输入什么 register_id/area_id 组合,我都会得到该寄存器的所有结果,因为这是页面的默认视图。)。这让我觉得原始查询可能没有得到正确处理?

【问题讨论】:

您没有说明这些表之间的关系是什么,也没有解释register_id 适合于此。如果您采用了一个有效的 SQL 查询,将其作为原始查询直接提供给数据库,并得到不同的结果,那么唯一合理的结论是您的(非常不安全地注入的)变量不包含您认为它们的值. 您是否尝试过将raw() 查询中的值替换为从您的数据库中挑选的一些值并运行它而不是您的参数(您应该转义) 【参考方案1】:

要翻译WHERE IN (SELECT ... ),需要使用whereIn

此外,尝试在子查询中使用 DB::table() 不会产生您期望的结果。

这个:

.., function ($query) use($q) 
        $query->DB::table('risk_areas')
        ...
)

应该是:

.., function ($query) use($q) 
        $query->from('risk_areas')
        ...
)

翻译后的查询应该是这样结束的:

DB::table('risks')
    ->where(function ($query) 
        $query->where('register_id', 29)
              ->where('area_id', 1);
    )
    ->orWhere(function ($query) 
        $query->whereIn('area_id', function ($sQuery) 
                  $sQuery->select('id')
                         ->from('risk_areas')
                         ->where('parent_id', 1);
              )
              ->where('register_id', 29);
    )
    ->orWhere(function ($query) 
        $query->whereIn('area_id', function ($sQuery) 
                  $sQuery->select('id')
                         ->from('risk_areas')
                         ->whereIn('parent_id', function ($sQuery2) 
                             $sQuery2->select('id')
                                     ->from('risk_areas')
                                     ->where('parent_id', 1);
                         );
              )
              ->where('register_id', 29);
    )
    ->get();
   

【讨论】:

以上是关于对 Laravel 查询构建器的 SQL 查询的主要内容,如果未能解决你的问题,请参考以下文章

Laravel 中数据库查询构建器的位置

使用 laravel 构建器的 JSON 列查询

Laravel 雄辩与查询构建器的优缺点

将原始 SQL 查询传递给 Laravel 上的查询构建器

laravel sql子查询

将 PHP SQL 转换为 Laravel 查询构建器 [重复]