質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.61%

ActionView::Template::Errorってつまりはどういうことですか?

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 8,154

score 61

Railsで作りHerokuにデプロイした試作アプリで以下のエラーが起きます。

 ActionView::Template::Error (PG::GroupingError: ERROR:  column "books.id" must appear in the GROUP BY clause or be used in an aggregate function

デプロイ前の開発環境(SQLite3)では問題なく動作している部分です。

そもそもbooks.idなどというcolumn自体使っていないのですが、これは何のことを言っているのでしょうか。
GroupingErrorとあるのでgroupしている部分がおかしいんだと予測しますが、どこの部分を指しているのかまるでわかりません。

@year = Book.group(:year).pluck(:year).sort


といった形で.groupは使っていますが、この部分をコメントアウトして再度デプロイしても同じエラーになります。

ActionViewということはviewの方でのエラーなのですか?

本物の初心者ですので(特にPostgreSQLは)エラーの指している箇所すらよくわかりません。

エラー文の後に続く

LINE 1: SELECT "books".* FROM "books" GROUP BY "books"."year"

これはまた何を言っているのでしょうか。SQL周りのことを初心者に優しく教えていただけると助かります。

追記

テーブルの情報
(不足があればおっしゃってください)※「CREATE TABLE文」とかよくわからないレベルの質問者です。

create_table "books", force: :cascade do |t|
t.text "name"
t.text "name_en"
t.string "year"
t.text "genre"
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • m.ts10806

    2019/02/07 19:55

    なるほどテーブル作成もプログラムから行ってるわけですね。
    私自身Rubyに明るいわけではないのであくまでSQL観点からの回答になりますがよろしいですか?すぐに取りかかれないのでちょっと夜遅くなるかもしれません

    キャンセル

  • Gr.

    2019/02/07 20:02

    mts10806さん
    感謝いたします。
    よろしくお願いいたします。

    キャンセル

  • m.ts10806

    2019/02/07 23:56

    お待たせしました。
    色々と整備したり準備してもらったほうが今後やりやすくなってくるかなと
    文章整理していたら長くなりました。

    キャンセル

回答 3

checkベストアンサー

+6

色々と前提があるんですが、今回を機にそこはきちんと整備してやってもらいたいがためにかなり長くなっています。

前提1

DBをプログラムからではなく直接見れる環境を整えよう。

「質問に提示してください」とお願いした「CREATE TABLE文」のことですが、
そのまま「テーブルを作る際に実行されているSQL文」のことです。
質問に追記いただいた情報から、おそらくRubyから実行されているのではないかなと。
データベースはプログラムからすると外部の情報として扱うことになります。
ということは何か問題が起きた時に、プログラムを確認するのではなく、実際のデータベースを見に行ってデータや設定などを確認することになります。
また、SQLと呼ばれるコードを実行して問い合わせを行いますが、それはプログラムから実行する場合も直に実行する場合も同じです。
プログラムから実行しようと思うと、画面遷移があったり入力があったり手間が発生します。
また、別途コメントで書いた通り、「DBに対して直接実行して失敗するSQLはプログラムから実行しても失敗する」ので、
直接DBに対して実行して、正しいSQLを生成してから、そのSQLの形になるようにプログラムを組むのが本来あるべき姿です。
だって、プログラムからDBを利用しようと思ったら、まずDB作ってテーブル作って、テストデータも入れることもありますよね?
プログラムを組む前にDBの準備ができているので、「こういうSQLを実行すればプログラム側でほしい情報をとってこれる(入れられる、更新できる、削除できる)」ものを作っておけば
それがある種のゴールになるのでプログラムもスムーズに作ることができます。

PostgreSQLであればPgAdminが有名どころですかね。
現場では複数の種類のDBの確認ができる[A5:SQL Mk-2]というのもよく採用されます。
いずれにしてもDBの情報を視認しやすいツールは必須です(もちろんコマンドから直接ログインもできますがGUIのほうが見やすい人は多いです)

そういったツールがあればプログラムから作ったテーブル情報でもCREATE TABLE文は出力しやすいです。

CREATE TABLE文を提供することができれば、今回でいえばRubyを実行できる環境がなくても情報の再現確認ができます。
できればサンプルデータのINSERT文があればなおよしです。回答のためにデータを考えたり、質問内容からくみ取るのって結構大変ですからね。

こういったツールは導入、活用してください。

前提2

エラーを読みましょう。

上記の記事にもありますが、英語が得意でなくてもGoogle翻訳にかけるだけでも意味が分かる言葉になります。

column "books.id" must appear in the GROUP BY clause or be used in an aggregate function
Google翻訳そのまま:列 "books.id"はGROUP BY句に含まれているか、集計関数で使用されている必要があります。

本題

確かに日本語としては読める文章になりましたが、
プログラムとしてはある程度理解していないと「どういうこと?」となりますね。

キーワードは幾つかあります。
「GROUP BY」または「集約関数」というものです。
そこで次はマニュアルを読みます。

集約関数とはざっくり言うと「特定の列に対して特定の条件で集約する処理をする関数」です。
総和(すべてを足したもの)を求めたり、平均を求めたり。
つまり、この集約関数を実行することで実行結果がまとまります。

ID 名前 得点
1 aさん 15
2 bさん 20
3 cさん 25

これを「得点」で「sum()」を使うと60が算出されます。

select sum(得点) as sum_point from user

  sum_point
  60

ここで「select句」にsum(得点) as sum_pointとだけ書きました。他の列は選んでいません。
※しれっと「 as xxxx」というのを使っていますが、これは「エイリアス」で、要は「別名」ですね。
テーブル名が長かった場合に省略した名前だったり、今回のように集約関数を使うとそのままsum(得点)というカラム名になるのでわかりやすくなるように別名をつけて扱いやすくしています。

それはなぜか?

「集約関数」であるがゆえに、列情報を集約します。
複数の入力行から 1 つの結果を計算するという仕様から、「1つの結果を集約した」ものであるわけです。
集約するので、集約の指定がないカラムは通常エラーになります(MySQLではエラーになりませんでしたが、SQLiteもならない感じでしょうね)

次は今回の問題であるGROUP BYです。

GROUP BY 句句は、テーブル内で選択された全列で同じ値を共有する行をまとめてグループ化するために使用されます。

「グループ化する」ということは「集約する」と同義になります。
実用的なケースはさておき、簡易例では下記。

ID 名前 出身地
1 aさん 東京
2 bさん 大阪
3 cさん 大阪
4 dさん 東京
5 eさん 名古屋

ここで「GROUP BY」を使う動機としては「出身地に何があるか知りたい」とかですね。

select 出身地 from user GROUP BY 出身地

すると下記のようになります。

出身地
東京
大阪
名古屋

それに加えて「それぞれの出身地が何人いるかも集計したい」となると今度は先にあげた「集約関数」を併用することで可能になります。

select 出身地,count(出身地) as count from user GROUP BY 出身地
すると下記のようになります。

出身地 count
東京 2
大阪 2
名古屋 1

ここで「集約関数」の説明部分をきちんと読んでいれば気づくかもしれません。
「とってきたい列以外指定していない・・?」

そうです。そこが今回の問題を解決する糸口になります。
GROUP BYを指定している場合、select句で指定するカラムは、ほかのカラムもGROUP BYで指定するか、集約関数で取得する必要があります。

ということで今回の問題のSQLを見てみましょう。

SELECT "books".* FROM "books" GROUP BY "books"."year"

books.* としています。booksはテーブル名として、
というのは専門用語だと「全列ワイルド・カード」です。
つまり、「全ての列を選択する」という意味になります。

質問本文に「books.idなどというcolumn自体使っていない」とありますし、
提示された「create_table 」から始まるコードには確かに「id」というカラムはないように見えます。

ここからはRuby on Railsの仕様になると思うのですが・・・
create_tableのページを見ますと、
[主キー自動生成がデフォルトtrueでその主キーのカラム名はid」と読み解けます。

という観点で見ると

create_table "books", force: :cascade do |t|
t.text "name"
t.text "name_en"
t.string "year"
t.text "genre"


上記、「主キーの自動生成、および主キーのカラム名」に対する指定がありませんよね。
ということは「主キーがidというカラムで自動生成されている」ということになると思います。

では「前提1」であげました、PgAdminなどのツールでDBの中を覗いてみてください。
おそらく「id」というカラムがあるはずですね。

ということで、
books.* という指定をすると「すべて」列が選択されるので、GROUP BYの仕様通り最初のエラー
列 "books.id"はGROUP BY句に含まれているか、集計関数で使用されている必要があります。
が成り立つわけですね。
集約されているカラムじゃないカラムもすべて選択されているわけですから。
なぜidしかエラーがでないかというと、プログラムは原則として、一番左上端から動いていくので、最初のカラムであるidの時点で、継続不可能なエラーが出て、そこで落ちた(中断した)と考えられます。

ではどうするか

ここからは「じゃあそもそもどういうデータを取得したいか」という
質問者さん自身の要件になってきます。仕様なので質問者さんが決める必要があります。

yearをグループ化したということは、例えば年毎に集約したデータを取りたいのでしょうし、でも年だけなの?というところは質問者さんにしかわかりません。
年だけでいいなら、
下記のようになるようにプログラムに組んでいくことになります。
SELECT "books"."year" FROM "books" GROUP BY "books"."year"

別途コメントしたように、Rubyに明るいわけではないですし、今提示されている情報だけでは「どう組めば良いか」まではわかりません。
「取得したデータをどう使いたいか」というところも「要件・仕様」になるので
その要件や仕様にあわせたデータの取り方にしてください。

※今回は「なぜ今回の問題が起きたか」というところが質問内容なので、だいぶ蛇足を含めて解説しました。tその「なぜ起きたか」がわかれば本件はいったん解決と考えています。


※ちなみに今回私が回答の際に作ったサンプルのCREATE TABLEとINSERTです。

CREATE TABLE "user"
(
    id integer NOT NULL,
    name character varying(10) COLLATE pg_catalog."default" NOT NULL,
    pref character varying(10) COLLATE pg_catalog."default" NOT NULL
);

INSERT INTO "user" ("id", "name", "pref") VALUES
(1, 'a', '東京'),
(2, 'b', '大阪'),
(3, 'c', '東京'),
(4, 'd', '大阪'),
(5, 'e', '名古屋'),
(6, 'f', '大阪'),
(7, 'g', '名古屋'),
(8, 'h', '福岡');

※ちなみにSQLはDBの種類によって方言があり、このCREATE TABLEも別の環境やDBでそのまま通るとは限りません。私の環境で抽出したものですし(PostgreSQL11 PgAdmin4)

既に回答がついているように開発環境と本番環境含めて全て同じ種類、同じバージョンでされた方がトラブルなく済みます。これはプログラムについても同じですね。
マイナーバージョンでも1つ違えば使えなくなる機能、非推奨の機能があってそれだけで同じ挙動は期待できません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/08 17:59

    mts10806さん
    回答ありがとうございます。
    とても詳しく丁寧な解説をいただき、感激です!
    ご指摘の通り、DBいじるにしても全てrubyでやっていました。railsの学習から始めたので…
    知らず知らずのうちに色々調整してくれているrialsの便利さを実感しつつも、根本的な理解がおろそかになるリスクも感じています。
    たとえば、簡単なテーブルを作ってデータ一覧(本のタイトル)をリストのように表示するページで、デプロイ後なぜかリロードするたびに並び順が変わる問題が発生したのですが、railsでは(SQLite3では?)デフォルトでid順に昇順で並ぶ仕様になっていることを忘れていたため、改めて並び順を指定することで解決した経験があります。このとき、railsって便利だけど不便だなと感じたものです。
    開発環境をしっかり整え、DB周りを中心に基礎知識からもっと勉強すべきだと身に沁みました。
    お時間を割いていただきありがとうございました。大変勉強になりました。

    キャンセル

  • 2019/02/08 18:03

    少しでもためになったのでしたら良かったです。
    DBは種類によって文法もそうですし並び順も保証されるわけではないので、やはり合わせたほうがいいですし、プログラムからの利用だけではなく、SQLやDBの扱い方そのものも覚えたほうがより適切なシステムが組めます。
    がんばってください。

    キャンセル

  • 2019/02/08 18:33

    >デフォルトでid順に昇順で

    これってDBの仕様だと思います。主キー、プライマリキーとかで調べるといいです。なにも指定していないとキーの順番が優先になります

    キャンセル

+3

railsは詳しくありませんけど、エラーの内容は分かります。

SELECT "books".* FROM "books" GROUP BY "books"."year"


GROUP BYを指定したときにselectできるのはgroup byした項目か集計関数のみです。
生成されているSQLでは*で指定しているのでエラーです。

SQLiteやMySQLはその辺が緩いんです。

開発環境もpostgresにした方が断然良さそうなんですが。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/07 23:51

    >SQLiteやMySQLはその辺が緩いんです。
    私も回答作っているときにMySQLで試しに集計カラム以外を指定してみたらエラーにならなくて若干焦りました(結局PostgreSQLで確認しましたが)

    キャンセル

  • 2019/02/08 18:06

    saziさん
    回答ありがとうございました。
    「ローカル環境とサーバー環境のDBの種類が違う」なんて可能性すら考えずに開発・デプロイしていました。たしかに、デプロイ先がPostgreSQLだったらPostgreSQLで開発すべきですね。あぁ、学ぶことが多い。。。

    キャンセル

+2

既に素晴らしい回答がついていますが、Railsまわりで補足を。

ActionView::Template::Errorってつまりはどういうことですか?

viewのテンプレートをレンダーする、つまり*.html.erbからhtmlを生成するときにエラーが起きたという意味です。
エラーの内容は、今回はPG::GroupingError: ERROR:...云々です。

また、手元のPostgresql(ver.9.6.8)のRails(ver.5.1.5)環境で、@year = Book.group(:year).pluck(:year).sortのようなコードを実行してみましたが、このようなエラーは出ませんでした。

この部分をコメントアウトして再度デプロイしても同じエラーになります。

とありますし、ここが原因でない可能性も考えたほうがいいのではないかと思います。
原因の特定に間違うとその後のすべての調査が無駄になってしまいますので、雰囲気で決めつけないようにしましょう。
Railsでは、SQLは必要になるまで実行されません。エラーが発生しているのはviewですが、controllerやmodel等で書いているコードが原因になっている可能性もあるので注意が必要です。

で、原因の特定作業ですが、saziさんがおっしゃるように、開発環境もpostgresqlにすることを強くおすすめします。
本番環境で調査できる範囲は限られるので、開発環境で同じエラーを再現できれば問題解決がスムーズに行えるはずです。
そこまで手間ではないはずなので、ぜひお試しください。
https://madogiwa0124.hatenablog.com/entry/2017/06/06/135138

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/02/08 18:11

    Kta-Mさん
    回答ありがとうございます。
    >viewのテンプレートをレンダーする、つまり*.html.erbからhtmlを生成するときにエラーが起きた
    エラーの意味を教えていただきありがとうございます。
    たしかにデプロイ先がpostgresqlなら開発環境もpostgresqlにすべきですね。リンク貼っていただき、ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.61%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る