sqlxでSUMを使う方法が分からなかった(わかった)
はじめに結論
SUMなどの集計関数を使うなら、モデルのタグに、`db:"SUM(hoge)"`とSUMも書きましょう
何故動かないのかわからなかった
例えば、次のようなデータのテーブル(sampleUser)があるとして、
name | score |
A | 10 |
B | 20 |
B | 30 |
次の形のデータが欲しかったんですね。
name | score |
A | 10 |
B | 50 |
SQLを叩くとこうなるわけですが、このクエリをsqlxで実行することに躓いてしまいました。
SELECT name, SUM(score) FROM sampleUser GROUP BY name;
// 実行しようとしたもの nameScore := []SampleUser{} // 結果を格納する構造体のスライス err := sqlx.SelectContext( ctx, r.db, &nameScore, ` SELECT name, SUM(score) FROM sampleUser GROUP BY name `, ) // "missing destination name SUM(score) in *[]SampleUser"と怒られる(とても親切なメッセージ)
結論を言うと、モデルのタグが不適切でした。
type SampleUser struct { Name string `db:"name"` Score uint32 `db:"score"` }
このような形で、nameとscoreを定義していたのですが、`db:"score"`と定義してしまっていました。
返ってくる値はscoreではなく、SUM(score)なので、`db:"SUM(score)"`とする必要がありました。
(この記事の最初から二つ目の表は間違っている)
mysql > SELECT name, SUM(score) FROM sampleUser GROUP BY name; +------+------------+ | name | SUM(score) | +------+------------+ | A | 10 | | B | 50 | +------+------------+
次のようにタグを変更することで、集計関数を含んだクエリを、sqlx.SelectContextで実行することができました。
type SampleUser struct { Name string `db:"name"` Score uint32 `db:"SUM(score)"` }
もちろん、タグを変更せず、AS句を使ってSQLの方を変更しても動きますね。
type SampleUser struct { Name string `db:"name"` Score uint32 `db:"score"` } nameScore := []SampleUser{} err := sqlx.SelectContext( ctx, r.db, &nameScore, ` SELECT name, SUM(score) AS score FROM sampleUser GROUP BY name `, )