在 Cakephp 4 中使用 contains()、order() 和 limit() 进行查询时出现问题

发布于 2025-01-09 15:31:37 字数 3146 浏览 3 评论 0原文

我有以下两个关联:

AgendaDates hasOne ImageDescriptive

AgendaDates hasMany Photos

当我执行此查询时:

$dates = $this->AgendaDates
                        ->find()
                        ->order(['AgendaDates.date' => 'ASC'])
                        ->contain(['ImageDescriptive' => function ($q) { // AgendaDates hasOne ImageDescriptive
                            return $q->find('translations');
                        }])
                        ->limit(2);

出现以下错误:

SQLSTATE[42000]:语法错误或访问冲突:1055 ORDER BY 子句的表达式 #1 不在 GROUP BY 子句中并且包含非聚合列“brigitte Patient.AgendaDates.date”在功能上不依赖于 GROUP BY 子句中的列;这与 sql_mode=only_full_group_by 不兼容

返回错误的 SQL 查询是:

SELECT 
  FichiersI18n.id AS FichiersI18n__id, 
  FichiersI18n.locale AS FichiersI18n__locale, 
  FichiersI18n.model AS FichiersI18n__model, 
  FichiersI18n.foreign_key AS FichiersI18n__foreign_key, 
  FichiersI18n.field AS FichiersI18n__field, 
  FichiersI18n.content AS FichiersI18n__content 
FROM 
  fichiers_i18n FichiersI18n 
  INNER JOIN (
    SELECT 
      (ImageDescriptive.id) 
    FROM 
      agenda_dates AgendaDates 
      LEFT JOIN fichiers ImageDescriptive ON (
        ImageDescriptive.model = 'AgendaDates' 
        AND ImageDescriptive.field = 'image_descriptive' 
        AND AgendaDates.id = ImageDescriptive.foreign_key
      ) 
    GROUP BY 
      ImageDescriptive.id 
    ORDER BY 
      AgendaDates.date ASC 
    LIMIT 
      2
  ) ImageDescriptive ON FichiersI18n.foreign_key = ImageDescriptive.id 
WHERE 
  FichiersI18n.model = 'Fichiers'

奇怪的是,当我做同样的事情但使用照片时(通过 hasMany 而不是 < 链接到 AgendaDates) code>hasOne) :

$dates = $this->AgendaDates
                        ->find()
                        ->order(['AgendaDates.date' => 'ASC'])
                        ->contain(['Photos' => function ($q) { // AgendaDates hasMany Photos
                            return $q->find('translations');
                        }])
                        ->limit(2);

我没有错误并且查询看起来像这样:

SELECT 
  FichiersI18n.id AS FichiersI18n__id, 
  FichiersI18n.locale AS FichiersI18n__locale, 
  FichiersI18n.model AS FichiersI18n__model, 
  FichiersI18n.foreign_key AS FichiersI18n__foreign_key, 
  FichiersI18n.field AS FichiersI18n__field, 
  FichiersI18n.content AS FichiersI18n__content 
FROM 
  fichiers_i18n FichiersI18n 
  INNER JOIN (
    SELECT 
      (Photos.id) 
    FROM 
      fichiers Photos 
    WHERE 
      (
        Photos.model = 'AgendaDates' 
        AND Photos.field = 'photos' 
        AND Photos.foreign_key in (5, 3)
      ) 
    GROUP BY 
      Photos.id
  ) Photos ON FichiersI18n.foreign_key = Photos.id 
WHERE 
  FichiersI18n.model = 'Fichiers'

我真的不明白为什么我的 cakephp 查询在以下情况下会抛出错误hasOne 关联,但在 hasMany 关联的情况下则不然?

I have the two following associations :

AgendaDates hasOne ImageDescriptive

AgendaDates hasMany Photos

When I do this query :

$dates = $this->AgendaDates
                        ->find()
                        ->order(['AgendaDates.date' => 'ASC'])
                        ->contain(['ImageDescriptive' => function ($q) { // AgendaDates hasOne ImageDescriptive
                            return $q->find('translations');
                        }])
                        ->limit(2);

I have the following error :

SQLSTATE[42000]: Syntax error or access violation: 1055 Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column 'brigittepatient.AgendaDates.date' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by

The SQL query that returns an error is :

SELECT 
  FichiersI18n.id AS FichiersI18n__id, 
  FichiersI18n.locale AS FichiersI18n__locale, 
  FichiersI18n.model AS FichiersI18n__model, 
  FichiersI18n.foreign_key AS FichiersI18n__foreign_key, 
  FichiersI18n.field AS FichiersI18n__field, 
  FichiersI18n.content AS FichiersI18n__content 
FROM 
  fichiers_i18n FichiersI18n 
  INNER JOIN (
    SELECT 
      (ImageDescriptive.id) 
    FROM 
      agenda_dates AgendaDates 
      LEFT JOIN fichiers ImageDescriptive ON (
        ImageDescriptive.model = 'AgendaDates' 
        AND ImageDescriptive.field = 'image_descriptive' 
        AND AgendaDates.id = ImageDescriptive.foreign_key
      ) 
    GROUP BY 
      ImageDescriptive.id 
    ORDER BY 
      AgendaDates.date ASC 
    LIMIT 
      2
  ) ImageDescriptive ON FichiersI18n.foreign_key = ImageDescriptive.id 
WHERE 
  FichiersI18n.model = 'Fichiers'

The strange thing is that when I do the same thing but with Photos (linked to AgendaDates by hasMany instead of hasOne) :

$dates = $this->AgendaDates
                        ->find()
                        ->order(['AgendaDates.date' => 'ASC'])
                        ->contain(['Photos' => function ($q) { // AgendaDates hasMany Photos
                            return $q->find('translations');
                        }])
                        ->limit(2);

I have no error and the query looks like that :

SELECT 
  FichiersI18n.id AS FichiersI18n__id, 
  FichiersI18n.locale AS FichiersI18n__locale, 
  FichiersI18n.model AS FichiersI18n__model, 
  FichiersI18n.foreign_key AS FichiersI18n__foreign_key, 
  FichiersI18n.field AS FichiersI18n__field, 
  FichiersI18n.content AS FichiersI18n__content 
FROM 
  fichiers_i18n FichiersI18n 
  INNER JOIN (
    SELECT 
      (Photos.id) 
    FROM 
      fichiers Photos 
    WHERE 
      (
        Photos.model = 'AgendaDates' 
        AND Photos.field = 'photos' 
        AND Photos.foreign_key in (5, 3)
      ) 
    GROUP BY 
      Photos.id
  ) Photos ON FichiersI18n.foreign_key = Photos.id 
WHERE 
  FichiersI18n.model = 'Fichiers'

I really don't understand why my cakephp query throws an error in the case of hasOne association but not in the case of hasMany association ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

放手` 2025-01-16 15:31:37

严格分组

only_full_group_by 模式要求 SELECTHAVINGORDER BY 中的所有字段必须是功能相关的 (列a 唯一确定列b),或聚合。

分组时,组中列的所有值不一定都相等,想象一下 Articles hasMany Comments 关系,如果您加入 Comments 并按 Articles 分组.idArticles 的所有列都可以通过 id 主键列确定,而 Comments 的列则不能,有可能有多个不同的每个 Article.idComments 列值,如下所示:

Articles.idComments.created
12022-01-01
12022-01-02
22022-02-01
22022-02-02

如果你有这样的结果,那么 MySQL 将不知道选择两个不同的 Comments.created 值中的哪一个当要求按组排序时,从该组中删除,因此发出可能产生此类结果的查询将引发错误。

当严格分组模式被禁用时,MySQL将被允许从组中基本上随机地选择一个值,这使得结果不可预测,这可能是一个问题。使用聚合可以解决这个问题,例如 MIN(Comments.created) 使用组中的最小日期值。

您可以在文档中以及通常在互联网上找到有关该主题的更多信息:

hasMany 与 hasOne

您的两个查询生成不同的 SQL,hasMany 关联始终在单独的查询中检索,那就是那里您正在调用 translations 查找器,这是一个单独的查询,其中没有发生连接、排序和限制,因此翻译分组不会导致任何问题,因为只有一个字段用于分组涉及。

hasOne 关联默认使用联接,因此是单个查询,因此您在该单个查询上调用 translations 查找器,即您要进行排序的查询和限制,这就是翻译分组与引用组中字段的顺序之间的冲突的根源。

tl;dr

通过对翻译行为使用 select 策略应该可以避免此问题,然后使用查询的主键而不是应用分组的子查询来获取翻译

$this->addBehavior('Translate', [
    'strategy' => 'select',
    // ...
]);

ImageDescriptive 关联的 INNER 联接也可能解决该问题(即查询可能生成的多个 null 值是函数依赖问题的根源),但它当然会改变涉及 null 值时查询记录的方式。

Strict Grouping

The only_full_group_by mode requires that all fields in SELECT, HAVING and ORDER BY must be either functionally dependent (column a uniquely determines column b), or aggregates.

When grouping, not all values for a column in a group will necessarily be equal, imagine an Articles hasMany Comments relation, if you join in Comments and group by Articles.id, all columns of Articles can be determined by the id primary key column, the columns of Comments however cannot, there could be multiple different Comments column values per Article.id, something like this:

Articles.idComments.created
12022-01-01
12022-01-02
22022-02-01
22022-02-02

If you had such results, then MySQL wouldn't know which of the two different Comments.created values to pick from the group when asked to order by it, hence issuing a query that could produce such a result will throw an error.

When strict group by mode is disabled, then MySQL would be allowed to pick a value from the group basically at random, which makes the results unpredictable, which can be a problem. Using an aggegrate can fix that, for example MIN(Comments.created) to use the smallest date value from the groups.

You can find more on that topic in the docs, and generally all over the internet:

hasMany vs hasOne

Your two queries produce different SQL, hasMany associations are always retrieved in a separate query, that is where you're calling the translations finder on, a separate query where no joining, ordering and limiting is happening, hence the grouping for the translations will not cause any problems since only the one field that is used for grouping is involved.

hasOne association are using joins by default, so a single query, hence here you're calling the translations finder on that single query, the one where you're doing the sorting and limiting, and that's where the clash between the grouping for the translations and the ordering that references a field from the group stems from.

tl;dr

It should be possible to avoid this problem by using the select strategy for the translate behavior, which will then obtain the translations using the queried primary keys instead of a subquery where grouping is applied:

$this->addBehavior('Translate', [
    'strategy' => 'select',
    // ...
]);

Using an INNER join for the ImageDescriptive association might possibly also fix the problem (that is in case the possible multiple null values that the query could produce are the source of the functional dependency problem), but it would of course change how records are queried when null values are involved.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文