こんにちは!
今回は「意図しないサブクエリが発行されてしまうときの対処法」についてお伝えしたいと思います。
エラーメッセージ:In aggregated query without GROUP BY, expression
僕が業務で実装する中で、Sequelize
でサブクエリを使って取得したいケースがありました。
その際、負荷軽減のためにLIMITを付けたところ、クエリが崩れてしまう現象が起きてしまったのです。
※発行SQLは変わらず
その経験を踏まえてお伝えしたいと思います。
Sequelizeで意図しないサブクエリが発行されてしまうときは、subQuery: falseで治るかもしれない
起きた事象
Sequelize
で以下のように記述しました。
親テーブル:room、小テーブル:user
const {fn, col} = db.Sequelize;
exports.getData = (keyword) => {
const sequelize = require('../utils/getDatabase')(db);
const dbName = sequelize.models;
return new Promise((resolve, reject) => {
dbName.room.findAll({
attributes: [
'id',
],
include: [{
model: dbName.user,
attributes: [
[fn('GROUP_CONCAT', col('users.name')), 'name'],
],
required: false,
}],
group: ['room.id'],
limit: 10,
raw: true,
}).then((res) => {
resolve(res);
}).catch((err) => {
reject(err);
});
});
};
→意図しない場所にサブクエリが生成されてエラーになる
In aggregated query without GROUP BY, expression
発行されたSQLは以下になります。
SELECT
`room`.*,
GROUP_CONCAT(`user`.`name`) AS `users.name`,
GROUP_CONCAT(`user`.`id`) AS `users.id`
FROM
(
SELECT
`room`.`id`,
`room`.`name`
FROM
`room` AS `room`
GROUP BY
`room`.`id`
LIMIT 10
) AS `room`
LEFT OUTER JOIN
`user` AS `users`
ON `room`.`id` = `users`.`room_id`
;
※ちなみにlimitを外すとうまくいきました。
解決策:subQuery: falseを以下のように修正
subQuery: false
というオプションを使います。
上記コードを以下のように修正します。
const {fn, col} = db.Sequelize;
exports.getData = (keyword) => {
const sequelize = require('../utils/getDatabase')(db);
const dbName = sequelize.models;
return new Promise((resolve, reject) => {
dbName.room.findAll({
attributes: [
'id',
],
include: [{
model: dbName.user,
attributes: [
[fn('GROUP_CONCAT', col('users.name')), 'name'],
],
required: false,
}],
group: ['room.id'],
subQuery: false, // ←追加
limit: 10,
raw: true,
}).then((res) => {
resolve(res);
}).catch((err) => {
reject(err);
});
});
};
発行されたクエリは以下のようになって、エラーも解消されました!
SELECT
`room`.`id`,
`room`.`name`,
GROUP_CONCAT(`users`.`name`) AS `users.name`
FROM
`room` AS `room`
LEFT OUTER JOIN
`user` AS `users`
ON `room`.`id` = `users`.`room_id`
GROUP BY
`room`.`id`
LIMIT 10
;
以上、お疲れさまでした〜🍵