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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Q&A

解決済

3回答

5272閲覧

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

Gr.

総合スコア89

Heroku

HerokuはHeroku社が開発と運営を行っているPaaSの名称です。RubyやNode.js、Python、そしてJVMベース(Java、Scala、Clojureなど)の複数のプログラミング言語をサポートしている。

SQLite

SQLiteはリレーショナルデータベース管理システムの1つで、サーバーではなくライブラリとして使用されている。

PostgreSQL

PostgreSQLはオープンソースのオブジェクトリレーショナルデータベース管理システムです。 Oracle Databaseで使われるPL/SQLを参考に実装されたビルトイン言語で、Windows、 Mac、Linux、UNIX、MSなどいくつものプラットフォームに対応しています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

0グッド

0クリップ

投稿2019/02/07 09:32

編集2019/02/07 10:27

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している部分がおかしいんだと予測しますが、どこの部分を指しているのかまるでわかりません。

controller

1@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"

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/02/07 09:44

SQLはプログラムから実行する前に直接DBに同じものを実行してみてください。そこで通らなければプログラムからも使えません。PostgreSQLであればPgAdminとかもありますし。
m.ts10806

2019/02/07 09:45

テーブルの情報は質問者さんしか知らない状態なので正確なアドバイスが難しいです。テーブル定義もご提示ください(CREATE TABLE文が良し)
Gr.

2019/02/07 10:32

mts10806さん 質問への追記・修正の依頼ありがとうございます。 追記しておきましたが不足があれば仰ってください。
m.ts10806

2019/02/07 10:55

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

2019/02/07 11:02

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

2019/02/07 14:56

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

回答3

0

ベストアンサー

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

前提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名前得点
1aさん15
2bさん20
3cさん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名前出身地
1aさん東京
2bさん大阪
3cさん大阪
4dさん東京
5eさん名古屋

ここで「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です。

sql

1 2CREATE TABLE "user" 3( 4 id integer NOT NULL, 5 name character varying(10) COLLATE pg_catalog."default" NOT NULL, 6 pref character varying(10) COLLATE pg_catalog."default" NOT NULL 7); 8 9INSERT INTO "user" ("id", "name", "pref") VALUES 10(1, 'a', '東京'), 11(2, 'b', '大阪'), 12(3, 'c', '東京'), 13(4, 'd', '大阪'), 14(5, 'e', '名古屋'), 15(6, 'f', '大阪'), 16(7, 'g', '名古屋'), 17(8, 'h', '福岡');

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

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

投稿2019/02/07 14:49

編集2019/02/08 01:11
m.ts10806

総合スコア80765

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Gr.

2019/02/08 08:59

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

2019/02/08 09:03

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

2019/02/08 09:33

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

0

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

SQL

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

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

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

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

投稿2019/02/07 12:46

sazi

総合スコア25138

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

m.ts10806

2019/02/07 14:51

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

2019/02/08 09:06

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

0

既に素晴らしい回答がついていますが、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 00:40

Kta-M

総合スコア456

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Gr.

2019/02/08 09:11

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問