如何在 Laravel 5 的嵌套查询中使用 GroupBy?

Posted

技术标签:

【中文标题】如何在 Laravel 5 的嵌套查询中使用 GroupBy?【英文标题】:How to use GroupBy in nested query in Laravel 5? 【发布时间】:2017-04-05 07:33:15 【问题描述】:

我在数据库中有四个表,即 Packages、Fixtures、Deals 和 Fixtures Deals。

这里是表结构细节:

Packages: id, title
Fixtures: id, package_id, name
Deals: id, discound, description
Fixtures_Deal: id, fixture_id, deal_id, price

我需要获取套餐清单以及每个套餐的每个灯具中提供的最低交易价格。

这是我在 phpMyAdmin 或 SQLYog 中运行的 mysql 查询,它运行良好,但在 Laravel 中它给出了“p.title' is not in GROUP BY”错误。

SELECT 
  p.title AS package_title,      
  tbl_min_value.min_price AS min_price 
FROM
  (SELECT 
    fixture_id,
    MIN(deal_price) AS min_price 
  FROM
    fixture_deal 
  GROUP BY fixture_id) AS tbl_min_value 
  JOIN fixtures AS f 
    ON f.id = tbl_min_value.fixture_id 
  RIGHT JOIN packages AS p 
    ON f.package_id = p.id 
GROUP BY p.id 

顺便说一句,我正在尝试通过在模型中使用以下方法来实现它:

return DB::statement('SELECT 
      p.title AS package_title,      
      tbl_min_value.min_price AS min_price 
    FROM
      (SELECT 
        fixture_id,
        MIN(deal_price) AS min_price 
      FROM
        fixture_deal 
      GROUP BY fixture_id) AS tbl_min_value 
      JOIN fixtures AS f 
        ON f.id = tbl_min_value.fixture_id 
      RIGHT JOIN packages AS p 
        ON f.package_id = p.id 
    GROUP BY p.id');

【问题讨论】:

您是否尝试过以另一种方式执行它,例如$pdo = DB::connection()->getPdo(); 并直接触发它 不,我没试过。你能详细说明我该怎么做吗?我应该写这样的代码吗?:DB::connection()->getPdo('Query'); codeshare.io/29QA72 不......它仍然给出几乎相同的错误:SQLSTATE [42000]:语法错误或访问冲突:1055 'p.title' is not in GROUP BY 如果将 p.title 替换为 id 会发生什么? 【参考方案1】:

我通过使用 Eloquent Collection 的 mapWithKeys 方法找到了另一种方法。

https://laravel.com/docs/5.3/collections#method-mapwithkeys

所以我分别获取了两个查询的数据,并将两个带有键的集合映射到一个集合对象中。

示例代码:

$packages = Package::getPackages();

$deal_min_price = Deal::getMinimumPrice();

$packages_with_price = $packages->mapWithKeys(function ($packages) use ($deal_min_price) 
    return $packages['price'] => $deal_min_price['min_price'];
);

您可以在mapWithKey's closure 中使用foreach 循环。

【讨论】:

【参考方案2】:

您得到的错误是因为 MySQL 5.7 移动到更符合 SQL99。您可以阅读一些关于 here 的信息,但它涉及一个名为 ONLY_FULL_GROUP_BY 的 SQL 模式设置,可确保选择的任何非聚合列都在 GROUP BY 内。这对您的情况意味着什么?

好吧,您只需将 p.titletbl_min_value.min_price 添加到分组中即可正常工作,因为它们没有聚合:

GROUP BY p.id, p.title, tbl_min_value.min_price

您可能想知道,“他们到底为什么要这样做?”。好吧,使用GROUP BY,在很容易意外地“折叠”数据之前,一行有多个可以显示的值,所以它只显示第一个。这使您可以使用 MIN()MAX() 等聚合函数确定要显示的内容,或者将其添加到分组中,表明您希望将它们分开。

如果你不喜欢它的工作方式,你可以这样做暂时禁用它:

# Run this query and copy the values
SELECT @@sql_mode;

# Remove "ONLY_FULL_GROUP_BY" and paste it in here where the XXX is
SET sql_mode = 'XXX';

或者您可以通过编辑 [mysqld] 部分下的 my.cnf 文件来使该更改永久化,其中 XXX 是 SELECT @@sql_mode; 的输出减去 ONLY_FULL_GROUP_BY 部分:

[mysqld]
sql_mode=XXX 

【讨论】:

一旦我在 Group By 中添加了其他聚合列,它并没有给我适当的结果,这意味着它输出的结果具有重复的 ID,这就是问题所在。另外,我尝试过修改 SQL 模式,但没有成功。 那是因为您的联接导致多行具有相同 ID。试试GROUP_CONCAT(p.title) 和/或GROUP_CONCAT(tbl_min_value.min_price) 看看我的意思 另外我想知道具有一个 Group By 列的相同查询在 phpMyAdmn 或 SQLYog 中运行良好,但在 Laravel 5.3 中不起作用。所以这可能是 Laravel 的问题......不确定..!【参考方案3】:

很奇怪,SQL 查询在 phpMyAdmin 中运行良好,但在 Laravel 5.3 中却无法运行。你会发布带有示例数据的 db 结构,让我们看一下吗?

顺便说一句,我尝试遵循 SQL 并且在 Laravel 5.2 中工作正常:

SELECT 
  p.title AS package_title,      
  tbl_min_value.min_price AS min_price 
FROM
  (SELECT 
    fixture_id,
    MIN(deal_price) AS min_price 
  FROM
    fixtures_deal 
  GROUP BY fixture_id) AS tbl_min_value 
  JOIN fixtures AS f 
    ON f.id = tbl_min_value.fixture_id 
  RIGHT JOIN packages AS p 
    ON f.package_id = p.id 
GROUP BY p.id 

【讨论】:

以上是关于如何在 Laravel 5 的嵌套查询中使用 GroupBy?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Laravel 的查询构建器执行嵌套连接?

Laravel 5.5 检索嵌套关系中的第一条记录

如何使用 Laravel 查询构建器编写嵌套连接?

如何在 laravel 8 的查询生成器中使用嵌套函数 substr()、cast() 和 Max()?

如何避免 laravel(php) 中的嵌套查询?

Laravel 5 嵌套搜索查询