如何使用Eloquent Laravel嵌套两个查询

时间:2017-12-29 15:31:58

标签: mysql laravel eloquent

我确实有一张桌子,里面有多个访客。在我的结果列表中,只显示每个访问者的最后一次访问。

表格如下:

id | created_at | descr | website | source
------------------------------------------
2  | 2017_12_22 | john | john1.com | a
3  | 2017_12_23 | marc | ssdff.com | b
4  | 2017_12_24 | john | john1.com | c
5  | 2017_12_24 | tina | def.com   | b
6  | 2017_12_25 | stef | abc.com   | a
7  | 2017_12_26 | john | john2.com | c

如果我做了

->orderBy('visitors.created_at', 'desc')
->groupBy('visitors.descr')

结果列表是正确的,因为每个访问者只显示一次。但我需要最新出现的访问者,结果列表显示第一次出现。因此,我希望看到ID 7而不是ID 2。

以下查询解决了该问题:

select *
from visitors as v 
INNER JOIN ( select descr , MAX(created_at) as max_created
from visitors as v
group by descr ) AS M 
where v.descr = M.descr AND v.created_at = M.max_created
ORDER BY created_at DESC

有人可以帮助将其变为雄辩或让我进入另一个方向吗?

3 个答案:

答案 0 :(得分:0)

为什么不直接像这样直接查询sql:

DB::table('visitors')->select("
  select *
  from visitors as v 
  INNER JOIN ( select descr , MAX(created_at) as max_created
  from visitors as v
  group by descr ) AS M 
  where v.descr = M.descr AND v.created_at = M.max_created
  ORDER BY created_at DESC
");

在eloquent中,查询将是这样的:

DB::table('visitors as v')
->join(DB::raw("( select descr , MAX(created_at) as max_created
from visitors as v
group by descr ) AS M "),'v.id','=','M.id')
->select('*')
->where('v.descr','M.descr')->where('v.created_at','M.max_created')
->orderBy('created_at','desc')
->get()

答案 1 :(得分:0)

如果您可以使用AUTO_INCREMENT id列而不是created_at,则可以使用其他方式获得(相同)结果:

select *
from visitors
where id in (
    select MAX(id)
    from visitors
    group by descr
)
ORDER BY id DESC

此查询的效率可能较低,但由于whereIn()支持子查询,因此更容易使用eloquent。

$subQuery = Visitor::groupBy('descr')->select(DB::raw('max(id)'));
$latestVisitors = Visitor::whereIn('id', $subQuery)->orderBy('id', 'desc')->get();

请注意,如果descr中的值相同,则原始查询可以按created_at返回多行。使用id不会发生这种情况,因为它是唯一的。

答案 2 :(得分:0)

您可以在访客模型中编写帮助关系

public function lastVisit()
{
    $this->hasOne('VisitModel')->latest();
}

然后只需访问上次访问的所有访问者

$visitors = Visitor::with('lastVisit')->get();

真的就是这一切。