1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

本番環境でMySQLのデフォルト設定ONLY_FULL_GROUP_BYを守っておらず一意になっていないと怒られたエラーの解決法

Last updated at Posted at 2020-10-02

問題

転職活動用のポートフォリオをAWSでのデプロイが完了したところ。
本番環境でchart.jsで作ったグラフを表示しようとしたところ、以下のエラーが表示された。

エラー

Mysql2::Error:Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'pfc-master_production.posts.created_at' which ins not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by: SELECT `posts`.`created_at` FROM `posts` WHERE `posts`.`user_id  = 2 GROUP BY date(created)

関連するソースコード

charts_controller.rb

charts_controller.rb
class ChartsController < ApplicationController

  def index
    # カロリー
    @sampleuser = User.find_by(id: 2)
    if user_signed_in?
      # 日付ごとで分けてカロリー合計を算出
      sum_calorie = current_user.posts.group("date(created_at)").sum(:calorie)
      # 日付ごとのカロリー合計がハッシュの形なので値を取得して配列に入れて変数に代入
      array_calorie = sum_calorie.values
    else
      sum_calorie = @sampleuser.posts.group("date(created_at)").sum(:calorie)
      array_calorie = sum_calorie.values
    end
      # gonを使ってデータをjs側に渡す
    gon.data = []
    # mapメソッドで日付ごとのカロリー合計を1つずつ取り出す
    # mapメソッドの使い方 → 配列変数.map {|変数名| 具体的な処理 }
    gon.data = array_calorie.map{ |calorie| calorie}
    binding.pry
    if user_signed_in?
      # 日付ごとにまとめてそのうちcreated_atカラムだけ取得。配列の形で格納されている
      dates_calorie = current_user.posts.group("date(created_at)").select(:created_at)
    else
      dates_calorie = @sampleuser.posts.group("date(created_at)").select(:created_at)
    end
    
    gon.date = []
    @dates = dates_calorie.map{ |dates| dates.created_at} ⬅️この部分でエラーが出た
    # each文で日付の表記を1つずつ取り出して変える
    @dates.each do |a|
      gon.date << a.strftime("%Y年%m月%d日")
    end
    binding.pry

    # 体重
    if user_signed_in?
      gon.weight = current_user.posts.group("date(created_at)").select(:weight).map{ |weight| weight[:weight]}
    else
      gon.weight = @sampleuser.posts.group("date(created_at)").select(:weight).map{ |weight| weight[:weight]}
    end
  end
end

解決手順

MySQLの設定ファイルであるmy.cnfを編集する。

vi /etc/my.cnf 

my.cnfを開いて
下記のコードを追加した。

/etc/my.cnf
[mysqld]
sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

my.cnfは読み取り専用ファイルなので、通常vimを上書き保存するshift+ZZ:wq!では上書き保存できなかった。

読み取り専用ファイルを上書き保存するには下記を入力して

:w !sudo tee %

そのうえで下記でvimファイルを閉じる。

:q!

my.cnfを編集し、MySQLの設定を変更したら、変更点を反映させるためにMySQLを再起動する。

service mysqld restart

なぜ解決できたのか

今回のエラー原因

MySQl5.7からデフォルトのままだとsql_modeでONLY_FULL_GROUP_BYが設定されるようになったため、一意にできていない場合にこのエラーになるそうです。

きちんと対応する方法としてはSQLをきちんと一意に特定できるように、GroupBy句に取得するカラムを指定したり、MAXやMIN、SUMなどで一意になるように修正する必要があります。

引用元:MySQL5.7にアップデートしたらonly_full_group_byでエラーになった

今回エラーが出たのはcharts_controller.rbの下記の部分だった。

charts_controller.rb
@dates = dates_calorie.map{ |dates| dates.created_at}

変数dates_calorieには下記のように、current_userの投稿を日付ごとにまとめて、created_atカラムを取得し配列に入れていったものが入っている。

charts_controller.rb
dates_calorie = current_user.posts.group("date(created_at)").select(:created_at)

同日に複数の投稿がある場合、.group("date(created_at)")で1つにまとめているので、同じ日付が複数存在することはあり得ず、一意になっているはずなので、なぜ「一意になるように修正しなさい」と言われるのかわからない。

実際、ローカル環境では問題なく動いているのに。

ONLY_FULL_GROUP_BY というデフォルトの自動設定をOFFにしてしまえばエラーが出なくなるという参考記事を見つけ、それを実行したところ、冒頭のエラーは表示されなくなった。

参考記事

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?