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

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

ただいまの
回答率

91.35%

  • Ruby

    5196questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails

    5076questions

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

  • MySQL

    4393questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。

【Rails, MySQL】 Limitを指定しつつ条件に当てはまる件数を取得したい

解決済

回答 3

投稿 2017/12/07 01:51 ・編集 2017/12/07 10:58

  • 評価
  • クリップ 0
  • VIEW 65

n_kitamura

score 11

「記事」と「コメント」のようなhas_manyな関係のテーブルがあるとします。
ここから、記事本文と、子のコメント本文両方を対象にしたLIKE検索を行おうとしています。

articles

id text
1 あああ

comments

id article_id text
1 1 いいい
2 1 ううう

検索自体は、以下のようにGROUP_CONCATを使うことで実現できました。

    articles = Article
    .joins(:comments)
    .group("comments.article_id")
    .having("CONCAT(articles.text, GROUP_CONCAT(comments.text)) like '%検索ワード%'")
    .limit(10).offset(10)

加えて、limit,offsetを考慮しない「検索条件にあてはまる全件数」をカウントする必要があります。

そこで、こちらの記事を参考に、

articles.except(:limit, :offset).count

などと試したのですが、groupやhavingがある場合(?)クエリエラーとなってしまいうまくいきません。

何かいい方法はないでしょうか?

そもそもGROUP_CONCATで検索している部分から否定して頂いても構いません。

何卒よろしくお願い致します。


追記:

.countで出力されたSQLは以下のような感じで、

SELECT COUNT(*) AS count_all, comments.article_id AS comments_article_id 
FROM `articles` INNER JOIN `comments` ON `comments`.`article_id` = `articles`.`id` 
GROUP BY comments.article_id 
HAVING (CONCAT(articles.description, GROUP_CONCAT(comments.description)) like '%ワード%')

1054 - Unknown column 'articles.description' in 'having clause'
となってしまいます。

  • このエラーが出るのはカウント時のみで、selectを「articles.*」に置き換えると問題なく通ります。
  • HavingをWhereに置き換えるとGROUP_CONCATが使えなくなってしまいます。
  • エラー箇所であるarticles.descriptionを消すとクエリは通るのですが、当然記事本文が検索対象に含まれなくなります。
  • そもそも、SELECTでcount_allのほかにcomments_article_idも指定されている理由もわかりません…。
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

+2

having とかはよくわかりませんが,最初のコードで正しく articles が得られるのであれば,

articles = Article
    .joins(:comments)
    .group("comments.article_id")
    .having("CONCAT(articles.text, GROUP_CONCAT(comments.text)) like '%検索ワード%'")
article_count = articles.count
articles = articles.limit(10).offset(10)

でいけませんかね。

投稿 2017/12/07 08:22

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/07 10:58

    ご回答ありがとうございます!
    試してみたのですが、やはりクエリエラーとなってしまいました。
    このエラーについて補足させて頂きました。

    キャンセル

checkベストアンサー

+1

検索条件にあてはまる全件数とは

  • articles 
aid text
1 あああ
2 かかか
3 さささ
  • comments
cid  aid  text
1 1 いいい
2 1 うういいいうう
3 1 ううう
4 2 ききき
5 2 くくいいいくく
6 3 ししし

だったときに、「いいい」を検索した時
ヒットする「aid=1:あああ」と「aid=2:かかか」の2件がほしいのか
cid=1、2、5の3件がほしいのでしょうか?

前者なら

SELECT COUNT(DISTINCT aid) FROM comments 
WHERE text LIKE '%いいい%';


後者なら単純に

SELECT COUNT(*) FROM comments 
WHERE text LIKE '%いいい%';

投稿 2017/12/07 09:37

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/07 11:25

    説明不足で申し訳ありません。前者です。
    なるほど、comment側を対象にarticle本文をjoinして検索すればGROUP_CONCATが不要になるんですね。

    ありがとうございます。

    キャンセル

0

scivolaさんの方法に似ていますが、単純にlengthで長さを取ることでも実現できました。

articles = Article
    .joins(略)
    .group(略)
    .having(略)
article_count = articles.length
articles = articles.limit(10).offset(10)

しかし、lengthを書いた時点でlimitのないクエリが実行されるようで、無駄にメモリが消費されているようにも思えます…。

投稿 2017/12/07 11:53

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

ただいまの回答率

91.35%

関連した質問

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

  • Ruby

    5196questions

    Rubyはプログラミング言語のひとつで、オープンソース、オブジェクト指向のプログラミング開発に対応しています。

  • Ruby on Rails

    5076questions

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

  • MySQL

    4393questions

    MySQL(マイエスキューエル)は、TCX DataKonsultAB社などが開発するRDBMS(リレーショナルデータベースの管理システム)です。世界で最も人気の高いシステムで、オープンソースで開発されています。MySQLデータベースサーバは、高速性と信頼性があり、Linux、UNIX、Windowsなどの複数のプラットフォームで動作することができます。