2017-07-12 10 views
0

私は、商品アイテムモデルとhas_many関係のPurchaseOrderモデルを持っています。 PurchaseOrderモデルとLine Itemモデルはどちらも、Deliveryモデルとhas_many関係にあります。 Deliveryモデルには "expected_arrival"属性があります。Tricky Rails 5 ActiveRecord "where"複数の関連モデルと "or"演算子を含むクエリ

a)注文の配信には、昨日またはそれ以前の "expected_arrival"属性があります。 b)注文の広告申込情報のいずれかに、 expected_arrival」昨日の属性またはそれ以前

私はRailsの5 or演算子を使用することを計画していたが、joinsまたはincludesorを組み合わせたときに明らかに既知のバグがRailsのであります。

https://github.com/rails/rails/issues/24055

私はそのようにように、grouphavingを使用してみました:

ActiveRecord::StatementInvalid: PG::UndefinedTable: ERROR: invalid reference to FROM-clause entry for table "deliveries" 

LINE 1:

PurchaseOrder.left_joins(:deliveries, {line_items: :deliveries}) 
    .group("purchase_orders.id") 
    .having("MAX(line_items.deliveries.expected_arrival) <= ? 
    OR MAX(deliveries.expected_arrival) <= ?", 
    Time.now, 
    Time.now)` 

これは、次のエラーが発生し...」purchase_orders.id HAVING BY NULL GROUPは(IS MAX(line_items ... ^ ヒント:テーブル "配送"のエントリがありますが、クエリのこの部分から参照することはできません。 `

これは、Railsは次のクエリのそれぞれが、自身で動作しますので、私は、このように配達テーブルにアクセスすることはできません私に言っているのは奇妙だ:

PurchaseOrder.left_joins(:deliveries).group("purchase_orders.id").having("MAX(deliveries.expected_arrival) <= ?", Time.now)` 

PurchaseOrder.left_joins({line_items: :deliveries}).group("purchase_orders.id").having("MAX(deliveries.expected_arrival) <= ?", Time.now)` 

私は、データベースにすることを避けるしたいと思います呼び出し、私はもともとorクエリを使用したかったのです。ご覧のとおり、最後の2つのクエリの両方で、私は単にline_items.deliveries.expected_arrivalの代わりにdeliveries.expected_arrivalを参照しています。私はこれがRailsに問題があると仮定しており、何とかline_items.deliveriesという別名を付ける必要があることを意味しています。

これは正しい仮定ですか?もしそうなら、私はそれについてどのように行くだろうか?そうでない場合は、このクエリを構造化する正しい方法は何ですか?

+0

う[この回答](https://stackoverflow.com/a/4795633/8088139)のようなものは、私は多くはバニラSQL対Railsのコマンドを好む –

+0

を助けます。 –

+0

は、 'Delivery'モデルが' PurchaseOrder'/'LineItem'との多相関連を持っていますか、それともそれぞれに対して外部キーを持っていますか? –

答えて

0

Railsには、同じテーブルへの複数の結合が可能な組み込みの結合メソッドはありませんが、SQLではそうはありません。 this answerから、ジョインステートメントにパラメーターを追加してジョインに名前を付けることで、これを行うことができます。

SELECT i.name as name, v1.value as value_1, v2.value as value_2 
    FROM item i 
     INNER JOIN item_value iv ON iv.item = i.id 
     INNER JOIN property p ON iv.property = p.id 
     LEFT JOIN value v1 ON p.name = 'prop1' AND v1.id = iv.value 
     LEFT JOIn value v2 ON p.name = 'prop2' AND v2.id = iv.value 

Railsは

PurchaseOrder 
    .joins("LEFT JOIN deliveries_purchase_orders on purchase_orders.id = deliveries_purchase_orders.purchase_order_id) 
    .joins("LEFT JOIN deliveries order_deliveries ON deliveries.id = deliveries_purchase_orders.delivery_id") 
    .left_joins(:line_items) 
    .joins("LEFT JOIN deliveries_line_items on line_items.id = deliveries_line_items.line_item_id) 
    .joins("LEFT JOIN deliveries item_deliveries ON deliveries.id = deliveries_line_items.delivery_id") 
    .group("purchase_orders.id") 
    .having("MAX(item_deliveries.expected_arrival) <= ? 
    OR MAX(order_deliveries.expected_arrival) <= ?", 
    Time.now, 
    Time.now)` 

としてきれいではない。このユースケースのためにthis answer

に見られるようにあった場合はそれができるよう、あなたが参加する文の一部としてSQLを置くことができませんそれを行うrailsy方法が、あなたが前進する必要があります。

EDIT:

これは全てのPostgreSQLで書かれたとフォーマットがSQL

代替ソリューションの他のフレーバーのためにわずかに異なるだろう。

このリクエストでは5つの結合要求が行われているため、PurchaseOrderLineItemに最新の予定納期のフィールドを追加し、作成/更新フィルタの後にRailsを使用して維持してください。読み込みと書き込みの処理負荷を取ります。

+0

意図的に、または偶然によって、「AS」ステートメントが欠落していましたか?私はあなたの正確なコード(いくつかのクローズド引用符btwがない)と次のもの(https://pastebin.com/V8rQ9SNj)を試しましたが、次のようなエラーが出ています: 'ActiveRecord :: StatementInvalid:PG :: UndefinedTable:ERROR :テーブル "deliveries_purchase_orders"のFROM節項目がありません LINE 1:... AS AS order_deliveries ON order_deliveries.id = deliveries ... ' –

+0

ジョインテーブル名が 'deliveries_purchase_orders '。ジョインテーブルとは何ですか? –

+0

ジョイン・テーブル名が問題の一部であるように見えます。私は以下のステートメントを受け取りました。 'PurchaseOrder.joins(" LEFT JOIN delivery_purchase_orders on purchase_orders.id = delivery_purchase_orders.purchase_order_id ")。ジョイン(" LEFT JOIN配送ASオーダー配送 "ON order_deliveries.id = delivery_purchase_orders.delivery_id") .left_joins(:line_items) ' しかし、私は次のように連結するとき、それは失敗します。 ' .joins( "LEFT line_items.id = delivery_line_items.line_item_idにdelivery_line_itemsを登録しよう") ' –

0

PurchaseOrder.includes(:deliveries, line_items: :deliveries) 
    .group("purchase_orders.id") 
    .where("MAX(line_items.deliveries.expected_arrival) <= ? 
    OR MAX(deliveries.expected_arrival) <= ?", 
    Time.now, 
    Time.now) 
+0

これは私の最初の質問に載せたものとほとんど同じですか?唯一の違いは 'include'と' left_joins'です。 –

関連する問題