将原始SQL添加到数据库查询构建器

时间:2018-07-27 17:05:55

标签: laravel

我有以下SQL,可以通过特定的过滤器和排序为我提供数据库中特定记录的位置。

\DB::select("SELECT
    t.id,
    t.position
  FROM (
    SELECT estimations.id,
    @rownum := @rownum + 1 AS position
    FROM estimations
    JOIN (SELECT @rownum := 0) r
    WHERE estimations.is_archived = 1
    ORDER BY estimations.start desc, estimations.name) t
  WHERE t.id = " . $this->id);

对于内部查询,我想使用雄辩的模型Estimation,以便可以使用其查询范围。我想使用该模型,以便如果将范围进行了下线更新,则此查询将反映出更改...

$innerQuery = Estimation::select('id')
    ->addSelect(\DB::raw('@rownum := @rownum + 1 AS position'))
    // Need to add "JOIN (SELECT @rownum := 0) r" 
    ->archived();

尝试1-失败

使用join方法并传递一些通用参数...

$innerQuery = Estimation::select('id')
   ->addSelect(\DB::raw('@rownum := @rownum + 1 AS position'))
   ->join('(SELECT @rownum := 0) r', '1', '=', '1')
   ->archived();

虽然以上内容为我提供了正确的SQL(如果我将其转储),则$innerQuery->toSql()在运行时会失败,$innerQuery->get()并显示以下错误...

  

SQLSTATE [42S02]:未找到基表或视图:1146表'my_db。(选择@rownum:= 0)r'不存在(SQL:SELECT temp.id,temp.position FROM(选择`id `,@rownum:= @rownum + 1来自估计值内部联接的AS位置((SELECT @rownum:= 0)r`在`1` =`1`上,其中`is_archived` =?由`start` desc排序, `name` asc)temp WHERE temp.id = 4)


尝试2-失败

如上所述,但对DB::raw()使用join()(由Jonas Staudenmeir建议),

$innerQuery = Estimation::select('id')
   ->addSelect(\DB::raw('@rownum := @rownum + 1 AS position'))
   ->join(\DB::raw('(SELECT @rownum := 0) r'), '1', '=', '1')
   ->archived();

运行$innerQuery->get()会导致以下错误...

  

SQLSTATE [42S22]:找不到列:1054“ on子句”中的未知列“ 1”(SQL:从“ estimations”内部联接中选择“ id”,@ rownum:= @rownum + 1个AS位置(SELECT @ rownum:= 0)r在`1` =`1`上,其中`is_archived` = 1顺序由`start` desc,`name` asc)


尝试3-失败

如上所述,为所有DB::raw()值添加join()(再次感谢Jonas Staudenmeir),

$innerQuery = Estimation::select('id')
   ->addSelect(\DB::raw('@rownum := @rownum + 1 AS position'))
   ->join(\DB::raw('(SELECT @rownum := 0) r'), \DB::raw('1'), '=', \DB::raw('1'))
   ->archived();

这可以单独使用$innerQuery->get();,但是当插入外部查询时

$res = \DB::select('SELECT
    t.id,
    t.position
  FROM (' . $innerQuery->toSql() . ') t
  WHERE t.id = ' . $this->id);

我收到错误消息...

  

SQLSTATE [HY000]:一般错误:2031(SQL:SELECT t.id,t.position FROM(选择“ id”,@ rownum:= @rownum + 1个来自“ estimations”内部联接的AS位置(SELECT @rownum := 0)r = 1 = 1,其中“ is_archived” =?由“ start” desc,“ name” asc排序)t WHERE t.id = 3)

这是因为scopeArchived()按一个值过滤,该值在错误中显示为?吗?如何避免这种情况?

这是scopeArchived()的代码

public function scopeArchived($query)
{
    return $query->where('is_archived', true)->ordered('start', 'desc');
}

删除->where('is_archived', true)不会导致任何错误,但显然不会导致我追求的结果。


尝试4-解决

(感谢Jonas Staudenmeir)-对外部查询使用fromSub()。这是完整的代码...

$innerQuery = Estimation::select('id')
    ->addSelect(\DB::raw('@rownum := @rownum + 1 AS position'))
    ->join(\DB::raw('(SELECT @rownum := 0) r'), \DB::raw('1'), '=', \DB::raw('1'))
   ->archived();

$res = \DB::query()->fromSub($innerQuery, 'temp')
    ->select('id', 'position')
    ->where('id', $this->id)
    ->first();

1 个答案:

答案 0 :(得分:1)

JOIN的“表”和“列”不能放在反引号中。您必须使用原始表达式:

->join(DB::raw('(SELECT @rownum := 0) r'), DB::raw('1'), '=', DB::raw('1'))