【问题标题】:Laravel Eloquent/Fluent select top 1 row per groupLaravel Eloquent/Fluent 选择每组前 1 行
【发布时间】:2014-07-16 18:59:17
【问题描述】:

我需要确定给定行的 signed_outsigned_in 日期是否超过一年。有时,当前可能会退出由NULL 值指定的区域。如果是这种情况,我需要查看下一个最高的signed_in 值,以确定该地区是否已在一年内退出。否则,我需要查看每个组的最后一个 signed_in 日期以确定这一点。

这些组基于territory_id 列。

我的桌子:

-----------------------------------------------------------------
| id | territory_id | signed_out          | signed_in           |
-----------------------------------------------------------------
| 5  | 8            | 2012-12-09 00:00:00 | 2013-02-28 00:00:00 |
| 9  | 8            | 2014-03-23 14:48:17 | 2014-06-11 00:00:00 |
| 11 | 10           | 2014-06-25 11:07:59 | NULL                |
| 14 | 10           | 2012-06-27 21:28:17 | 2012-10-10 00:00:00 |
| 15 | 11           | 2014-06-27 21:28:48 | NULL                |
| 13 | 11           | 2012-09-12 20:23:07 | 2012-12-27 00:00:00 |
| 20 | 11           | 2011-10-30 21:05:29 | 2012-01-05 00:00:00 |
-----------------------------------------------------------------

预期结果:行91115

我看过很多group bygreatest-n-per-group 标记mysql 问题的示例,但我无法理解如何构建此查询,尤其是在Laravel 中使用Eloquent 或Fluent。如果我必须使用 Raw 查询,我想这很好。

我尝试过的:

TerritoriesSignInOut::where('signed_in', '<=', Carbon::now()->subYear())
                    ->orWhere(function($query)
                    {
                        $query->where('signed_out', '<=', Carbon::now()->subYear())
                              ->whereNull('signed_in');
                    })
                    ->groupBy('territory_id')
                    ->orderBy('signed_in', 'DESC')
                    ->get();

但这并没有执行正确的子查询选择,这是我认为该语句的问题。

非常感谢任何帮助,因为我已经为此绞尽脑汁好几个小时了。

【问题讨论】:

  • 如果工作正常,是否有任何方法可以显示您希望从 MySQL 返回的结果的另一个网格?
  • 我只是添加了预期的结果。我会看看你的答案。

标签: php mysql sql laravel greatest-n-per-group


【解决方案1】:

我相信这个查询应该适合您,尽管您可能想先对其进行测试。您提供的数据似乎对我有用。

SELECT id, GREATEST(signed_in, COALESCE(signed_out, signed_in)) AS `my_date`
FROM (SELECT * FROM `territories` ORDER BY signed_in DESC) territories
GROUP BY territory_id
HAVING my_date <= DATE_SUB(NOW(), INTERVAL 1 YEAR);

要在 Fluent 中构建查询,这应该可以工作。它使用了相当多的原始数据,但我认为如果您不绑定任何数据,就没有注入的机会。

DB::table(DB::raw('(SELECT * FROM `territories` ORDER BY signed_in DESC) territories'))
    ->select(DB::raw('id, GREATEST(signed_in, COALESCE(signed_out, signed_in)) AS `my_date`'))
    ->groupBy('territory_id')
    ->having('my_date', '<=', DB::raw('DATE_SUB(NOW(), INTERVAL 1 YEAR)'))
    ->get();

不过,您必须更改表格的名称,我只是使用区域,因为它很简单,但它显然不是区域表。

【讨论】:

  • 太棒了!效果很好。我必须将第一个 DB::raw ORDER BY 更改为 ASC 并删除 COALESCE 函数,因为在某些情况下,我确实需要在 signed_in 列中包含 NULL 值的行。
猜你喜欢
  • 2020-12-16
  • 2014-02-10
  • 1970-01-01
  • 2012-12-04
  • 2015-08-15
  • 1970-01-01
  • 2018-10-20
  • 1970-01-01
  • 2013-06-10
相关资源
最近更新 更多