在 Cakephp 4 中使用 contain()、order() 和 limit() 进行查询时出现问题
Problem with a query using contain(), order() and limit() in Cakephp 4
我有以下两个关联:
议程日期hasOne
图片描述
议程日期hasMany
照片
当我执行此查询时:
$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 子句中并且包含非聚合列 'brigittepatient.AgendaDates.date'在功能上不依赖于 GROUP BY 子句中的列;这与 sql_mode=only_full_group_by
不兼容
SQL查询returns一个错误是:
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
而不是 hasOne
链接到 AgendaDates):
$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
关联的情况下却不会?
严格分组
only_full_group_by
模式要求 SELECT
、HAVING
和 ORDER BY
中的所有字段必须是功能相关的(列 a
唯一确定列 b
), 或聚合。
分组时,并非组中某一列的所有值都必须相等,想象一个 Articles hasMany Comments
关系,如果您加入 Comments
并按 Articles.id
分组,所有Articles
的列可以由 id
主键列确定,但是 Comments
的列不能,每个 Article.id
可能有多个不同的 Comments
列值,像这样:
Articles.id
Comments.created
1
2022-01-01
1
2022-01-02
2
2022-02-01
2
2022-02-02
如果你有这样的结果,那么 MySQL 将不知道在被要求订购时从组中选择两个不同的 Comments.created
值中的哪一个,因此发出一个查询可以产生这样的结果会报错。
当禁用严格分组模式时,MySQL 将被允许从组中基本上随机选择一个值,这使得结果不可预测,这可能是一个问题。使用聚合可以解决这个问题,例如 MIN(Comments.created)
使用组中的最小日期值。
您可以在文档中找到关于该主题的更多信息,通常在整个互联网上:
- https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
- https://dev.mysql.com/doc/refman/5.7/en/group-by-functional-dependence.html
hasMany 与 hasOne
你的两个查询产生不同的 SQL,hasMany
关联总是在一个单独的查询中检索,也就是你调用 translations
查找器的地方,一个单独的查询没有加入、排序和限制发生,因此翻译的分组不会造成任何问题,因为只涉及一个用于分组的字段。
hasOne
关联默认使用连接,所以是单个查询,因此在这里您要在该单个查询上调用 translations
查找器,即您正在进行排序的查询和限制,这就是翻译分组与引用组中字段的排序之间冲突的根源。
tl;博士
应该可以通过对翻译行为使用 select
策略来避免此问题,然后该策略将使用查询的主键而不是应用分组的子查询来获取翻译:
$this->addBehavior('Translate', [
'strategy' => 'select',
// ...
]);
对 ImageDescriptive
关联使用 INNER
连接也可能解决问题(如果查询可能产生的多个 null
值是函数依赖性问题),但它当然会改变涉及 null
值时查询记录的方式。
我有以下两个关联:
议程日期hasOne
图片描述
议程日期hasMany
照片
当我执行此查询时:
$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 子句中并且包含非聚合列 'brigittepatient.AgendaDates.date'在功能上不依赖于 GROUP BY 子句中的列;这与 sql_mode=only_full_group_by
不兼容SQL查询returns一个错误是:
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
而不是 hasOne
链接到 AgendaDates):
$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
关联的情况下却不会?
严格分组
only_full_group_by
模式要求 SELECT
、HAVING
和 ORDER BY
中的所有字段必须是功能相关的(列 a
唯一确定列 b
), 或聚合。
分组时,并非组中某一列的所有值都必须相等,想象一个 Articles hasMany Comments
关系,如果您加入 Comments
并按 Articles.id
分组,所有Articles
的列可以由 id
主键列确定,但是 Comments
的列不能,每个 Article.id
可能有多个不同的 Comments
列值,像这样:
Articles.id | Comments.created |
---|---|
1 | 2022-01-01 |
1 | 2022-01-02 |
2 | 2022-02-01 |
2 | 2022-02-02 |
如果你有这样的结果,那么 MySQL 将不知道在被要求订购时从组中选择两个不同的 Comments.created
值中的哪一个,因此发出一个查询可以产生这样的结果会报错。
当禁用严格分组模式时,MySQL 将被允许从组中基本上随机选择一个值,这使得结果不可预测,这可能是一个问题。使用聚合可以解决这个问题,例如 MIN(Comments.created)
使用组中的最小日期值。
您可以在文档中找到关于该主题的更多信息,通常在整个互联网上:
- https://dev.mysql.com/doc/refman/5.7/en/group-by-handling.html
- https://dev.mysql.com/doc/refman/5.7/en/group-by-functional-dependence.html
hasMany 与 hasOne
你的两个查询产生不同的 SQL,hasMany
关联总是在一个单独的查询中检索,也就是你调用 translations
查找器的地方,一个单独的查询没有加入、排序和限制发生,因此翻译的分组不会造成任何问题,因为只涉及一个用于分组的字段。
hasOne
关联默认使用连接,所以是单个查询,因此在这里您要在该单个查询上调用 translations
查找器,即您正在进行排序的查询和限制,这就是翻译分组与引用组中字段的排序之间冲突的根源。
tl;博士
应该可以通过对翻译行为使用 select
策略来避免此问题,然后该策略将使用查询的主键而不是应用分组的子查询来获取翻译:
$this->addBehavior('Translate', [
'strategy' => 'select',
// ...
]);
对 ImageDescriptive
关联使用 INNER
连接也可能解决问题(如果查询可能产生的多个 null
值是函数依赖性问题),但它当然会改变涉及 null
值时查询记录的方式。