Issue
I have the two following associations :
AgendaDates hasOne ImageDescriptive
AgendaDates hasMany Photos
When I do this query :
class="lang-php prettyprint-override">$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 ?
Solution
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.id | Comments.created |
|---|---|
| 1 | 2022-01-01 |
| 1 | 2022-01-02 |
| 2 | 2022-02-01 |
| 2 | 2022-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:
- 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 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.
Answered By - ndm Answer Checked By - Robin (PHPFixing Admin)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.