7

レガシー データベースを Rails アプリケーション (3.2.3) に移行する作業を行っています。元のデータベースには、レポート用のかなりの数の長い SQL クエリが付属しています。今のところ、Rails アプリケーションで sql クエリを使用し、(時間が許せば) 1 つずつ sql クエリを「適切な」Rails クエリに交換したいと考えています。

臨床モデルがあり、コントローラーには次のコードがあります。

 @clinical_income_by_year = Clinical.find_all_by_sql(SELECT date_format(c.transactiondate,'%Y') as Year, 
                                                 date_format(c.transactiondate,'%b') as Month,
                                                 sum(c.LineBalance) as "Income"
                                                 FROM clinical c
                                                 WHERE c.Payments = 0 AND c.LineBalance <> 0
                                                 AND c.analysiscode <> 213
                                                 GROUP BY c.MonthYear;)

ただし、そのコードを実行すると、フォーマットに関連するいくつかのエラーが発生します。

Started GET "/clinicals" for 127.0.0.1 at 2012-04-29 18:00:45 +0100

SyntaxError (/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:6: syntax error, unexpected tIDENTIFIER, expecting ')'
...rmat(c.transactiondate,'%Y') as Year, 
...                               ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:7: syntax error, unexpected tIDENTIFIER, expecting keyword_end
...rmat(c.transactiondate,'%b') as Month,
...                               ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:8: syntax error, unexpected tIDENTIFIER, expecting keyword_end
...          sum(c.LineBalance) as "Income"
...                               ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:10: syntax error, unexpected tCONSTANT, expecting keyword_end
...       WHERE c.Payments = 0 AND c.LineBalance <> 0
...                               ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:10: syntax error, unexpected '>'
...yments = 0 AND c.LineBalance <> 0
...                               ^
/Users/dannymcclelland/Projects/premvet/app/controllers/clinicals_controller.rb:11: syntax error, unexpected '>'
...          AND c.analysiscode <> 213
...                               ^

コントローラーにインポートする前に、SQL クエリに対して行うべきことはありますか? クエリに問題がある可能性はありますが (かなり前に作成されたものです)、データベース内で直接実行すると期待どおりに動作します。次のような配列を返します。

----------------------------------------------
|  Year      |    Month     |     Income     |
----------------------------------------------
----------------------------------------------
|  2012      |    January   |   20,000       |
|  2012      |    February  |   20,000       |
|  2012      |    March     |   20,000       |
|  2012      |    April     |   20,000       |
----------------------------------------------
etc..

ヘルプ、アドバイス、または一般的な指針をいただければ幸いです。

http://guides.rubyonrails.org/active_record_querying.htmlを読んで、SQLクエリを正しいRailsクエリに変換しようとしています。

これまでのところ、最後から 2 番目の行を一致させました。

AND c.analysiscode <> 213

@clinical_income_by_year = Clinical.where("AnalysisCode != 213")

赤ちゃんのステップ!

アップデート

Rails ガイド サイトのおかげで、今はフィルタリングがソートされていますが、SQL クエリのグループ化と合計の部分に行き詰まっています。これまでのところ、次のものがあります。

@clinical_income_by_year = Clinical.where("AnalysisCode != 213 AND Payments != 0 AND LineBalance != 0").page(params[:page]).per_page(15)

SQLクエリの次の2行を構築するのに苦労しています:

sum(c.LineBalance) as "Income"

GROUP BY c.MonthYear;)

私のビューコードは次のようになります:

<% @clinical_income_by_year.each do |clinical| %>
  <tr>
    <td><%= clinical.TransactionDate.strftime("%Y") %></td>
    <td><%= clinical.TransactionDate.strftime("%B") %></td>
    <td><%= Clinical.sum(:LineBalance) %></td>
  </tr>    
  <% end %>
</table>
  <%= will_paginate @clinical_income_by_year %>
4

1 に答える 1

14

Ruby パーサーは SQL を理解できません。文字列を使用する必要があります。

@clinical_income_by_year = Clinical.find_by_sql(%q{ ... })

埋め込まれた引用符についてあまり心配する必要がないように、これには%qor (補間が必要な場合)を使用することをお勧めします。%Qまた、それをモデルのクラス メソッドに移動して、コントローラーが自分の仕事ではないことを心配しないconnection.quoteようにする必要があります。これにより、友人に簡単にアクセスできるようになり、文字列補間を適切に使用できるようになります。

find_by_sql(%Q{
    select ...
    from ...
    where x = #{connection.quote(some_string)}
})

また、SQL のセミコロン:

GROUP BY c.MonthYear;})

必要ありません。一部のデータベースはそれを通過させますが、とにかくそれを取り除く必要があります.

データベースによっては、識別子 (テーブル名、列名など) は大文字と小文字を区別しない必要があります (作成時に悪意のある人が引用しない限り)。より良いレール。

また、一部のデータベースでは、SELECT に集計またはグループ化されていない列があるため、その GROUP BY が気に入らないc.transactiondateため、各グループにどちらを使用するかがあいまいになることに注意してください。


より「Railsy」なバージョンのクエリは次のようになります。

@c = Clinical.select(%q{date_format(transactiondate, '%Y') as year, date_format(transactiondate, '%b') as month, sum(LineBalance) as income})
             .where(:payments => 0)
             .where('linebalance <> ?', 0)
             .where('analysiscode <> ?', 213)
             .group(:monthyear)

次に、次のようなことができます。

@c.each do |c|
    puts c.year
    puts c.month
    puts c.income
end

結果にアクセスします。日付マングリングを Ruby にプッシュすることで、少し単純化することもできます。

@c = Clinical.select(%q{c.transactiondate, sum(c.LineBalance) as income})
             .where(:payments => 0)
             .where('linebalance <> ?', 0)
             .where('analysiscode <> ?', 213)
             .group(:monthyear)

次に、 andc.transactiondateを呼び出すのではなく、Ruby で引き離します。c.yearc.month

于 2012-04-29T17:37:53.247 に答える