【问题标题】:Query builder - combining orderBy and groupBy查询生成器 - 结合 orderBy 和 groupBy
【发布时间】:2018-06-26 09:55:03
【问题描述】:

我有一个 Laravel 应用程序,并且我有一个应该按如下方式运行的查询。

company   date      period
apple | 2017-08-23 | live
apple | 2017-09-04 | live
apple | 2014-03-04 | history
enron | 1987-09-09 | history
tesla | 2017-07-04 | live
tesla | 2017-06-03 | live

它需要按日期降序对每个公司的条目进行排序,条件是 period='live',从而返回每个公司的最后一个“live”条目。在上面的例子中,这应该返回

company   date 
apple | 2017-09-04
tesla | 2017-07-04

我已尝试使用查询生成器来完成此操作,例如:

return $query->where('period', '=', 'live')
        ->groupBy('company')
        ->orderBy('date','desc');

但是,这首先对结果进行分组,然后对它们进行排序,这会产生不可预测的结果。根据这个问题/答案,答案在于子查询:

ORDER BY date and time BEFORE GROUP BY name in mysql

但是,我无法将这种方法整合到我的问题中。您能否向我解释如何有效地解决这个问题,无论是使用子查询还是使用不同的方法,但不使用原始查询?

【问题讨论】:

  • 我想这就是你要找的东西:laravel.com/api/5.5/Illuminate/Database/Query/…
  • @ThomasMoors 抱歉,我完全不懂语法。请详细回答一下好吗?
  • 您只想选择company, MAX(date)company 分组。您不需要对结果进行排序,除非您希望对结果组进行排序。

标签: php mysql laravel eloquent laravel-eloquent


【解决方案1】:

您当前对所需输出的策略是正确的,并且您不需要子查询。以下原始 MySQL 查询就足够了:

SELECT company, MAX(date)
FROM companies
GROUP BY company

我们可以试试下面的 Laravel 代码:

return $query->where('period', '=', 'live')
    ->groupBy('company')
    ->orderBy('date','desc')
    ->get(['company', DB::raw('MAX(date) AS max_date')]);

与您在问题中所说的相反,如果您使用ORDER BY 查询并且表中的基础数据没有改变,那么查询的结果应该是完全可重现的。

编辑:

与您的问题相反,您的 cmets 表示您希望每个公司的每个最大日期的整个匹配行。如果是这样,那么您真的需要以下原始 MySQL 查询:

SELECT c1.*
FROM companies c1
INNER JOIN
(
    SELECT company, MAX(date) AS max_date
    FROM companies
    GROUP BY company
) c2
    ON c1.company = c2.company AND
       c1.date = c2.max_date

我们可以尝试编写以下 Laravel 代码来处理这个问题:

DB::table('companies')
    ->select('*')
    ->join(DB::raw('(SELECT company, MAX(date) AS max_date
                     FROM companies GROUP BY company) c2'), function($join)
        {
            $join->on('companies.company', '=', 'c2.company');
            $join->on('companies.date', '=', 'c2.max_date');
        })
    ->orderBy('companies.date', 'DESC')
    ->get();

【讨论】:

  • 由于某种原因,使用 MAX 的查询仍然返回它找到的第一行而不是最后一个日期。我尝试直接在 phpMyAdmin 中运行它,以确保它不是我的应用程序的问题。
  • 准确地说,它正确地返回了最大日期,但它从找到的第一行返回了该行的其余部分。我知道在我的示例中这只是“公司”列,但实际上我还有几个包含不同值的列。因此,返回最后一个日期的整个实际行很重要,而不仅仅是日期本身。很抱歉造成混乱。
  • @jovan 我更新了我的答案,希望能满足您的需求。
  • laravel 本身甚至不推荐使用原始查询。
【解决方案2】:

另一种解决方案可能是简单地groupBy() 排序后的查询结果 (https://laravel.com/docs/5.5/collections#method-groupby) 这完全取决于您生成的数据集的大小

【讨论】:

    【解决方案3】:

    https://laravel.com/docs/5.5/queries#retrieving-results 看看这个链接。你应该使用 DB::table('company')->where('period','live')->groupBy('your condition')->orderBy('your condition')->get(); 它将返回 StdClass 对象。如果你想要一个数组,在 get() 之后添加 toArray(); 希望它有效并让我知道。

    【讨论】:

    • 我没有投反对票,但我认为这是因为答案完全没有抓住问题的重点。
    猜你喜欢
    • 1970-01-01
    • 2018-10-23
    • 2019-05-26
    • 2018-01-01
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多