2016-08-09 3 views
0

左のANDパラメータが下の別のテーブルチェックテーブルのサンプルに参加するPSQLクエリがあります。LEFT ANDパラメータが別のテーブルにある場合のPSQLに参加する

請求書

id | account |  invoice_date  | reference | total_amount | status 
-----+---------+-------------------------+-----------+--------------+-------- 
164 |  100 | 2016-08-03 03:05:08.996 |  161 |  2000.00 |  
165 |  100 | 2016-08-03 21:42:07.865 |  164 |   0 |  
167 |  100 | 2016-08-03 22:56:41.731 |  166 |  100.00 |  
168 |  100 | 1970-01-01 00:33:20  |  161 |   200 |  
169 |  100 | 2016-08-08 00:00:00  |  161 |   200 | 

Invoice_items

id | invoice | invoice_item_type | product | quantity | unit_price | reference | amount 
-----+---------+-------------------+---------+----------+------------+-----------+--------- 
143 |  164 |     1 |  6 |   |   |  161 | 2000.00 
144 |  165 |     1 |  11 |   |   |  164 |  0 
145 |  167 |     1 |  8 |   |   |  166 | 100.00 

もID

がある別のテーブル製品だけで、関連するフィールドがあり、これは私のクエリです

select products.id, sum(invoice_items.amount) as total_revenue 
from products 
    left join invoice_items on invoice_items.product = products.id 
    left join invoices on invoice_items.invoice = invoices.id 
         and invoices.invoice_date= current_date 
group by products.id; 

クエリが必要なのは、すべての商品IDを一覧表示し、total_revenue列に商品の売上の合計を入力します(現在の日の '商品'フィールドが似ているinvoice_itemsテーブルに 'amount'を追加します) INVOICESテーブル)。しかし、このクエリを実行すると、製品のtotal_amountsがすべてリストされます。私は何が欠けていますか?

サンプル出力。 8、6、11は空白にする必要があります。

id | total_revenue 
-----+--------------- 
125 |    
154 |    
119 |    
129 |    
    8 |  100.00 
112 |    
    5 |    
132 |    
104 |    
113 |    
143 |    
152 |    
121 |    
127 |    
165 |    
139 |    
146 |    
    15 |    
    2 |    
147 |    
149 |    
166 |    
169 |    
    13 |    
106 |    
122 |    
    9 |    
    11 |    0 
110 |    
120 |    
130 |    
155 |    
134 |    
136 |    
101 |    
168 |    
131 |    
157 |    
161 |    
103 |    
150 |    
159 |    
107 |    
108 |    
145 |    
    4 |    
    12 |    
158 |    
167 |    
138 |    
162 |    
100 |    
156 |    
163 |    
124 |    
123 |    
109 |    
153 |    
102 |    
105 |    
151 |    
116 |    
133 |    
140 |    
160 |    
148 |    
126 |    
141 |    
    7 |    
118 |    
    10 |    
164 |    
128 |    
    14 |    
144 |    
135 |    
    1 |    
    6 |  2000.00 
    3 |    
137 |    
117 |    
142 |    
111 |   
+1

_8、6、11は何を意味するのですか? 'left join'の日付に' and'をつけているので、一致しなかった商品を追加します。照会を見ると、請求書を持っている製品の収入のみが必要な場合は、内部結合でも十分です。 – Neeraj

答えて

0

invoiceテーブルのレコードをフィルタリングする必要がありますが、両方の結合が残っているため、これは実行されません。派生テーブルはこれを簡単に解決し、必要な結果を返します。また、簡潔さと可読性のためにいくつかのテーブルエイリアスを追加しました。このよう

SELECT 
    p.id, SUM(inv.amount) AS total_revenue 

FROM 
    products p LEFT JOIN 

    (SELECT 
     ii.product, i.invoice_date, ii.amount 
    FROM 
     invoice_items ii JOIN 
     invoices i ON 
      ii.invoice = i.id) inv ON 
      inv.product = p.id AND 
      inv.invoice_date= current_date 

GROUP BY p.id; 
+1

これはトリックでした。派生テーブルのii.invoice_dateをi.invoice_dateに変更するだけです。ありがとう:* –

+0

おっと、はい本当に - 私は今それを修正しました。 –

0

あなたは多くのNULL値を取得しています。

これは、「左」結合ではなく「INNER」結合型の問題のようです。左結合は、結果セット内の製品に対する請求書がない場合のすべてのインスタンスを保持します。

あなたはまた、having句(個人的に、私はロジックが明確に見つけるよう/持つWHEREでサブクエリを好む)に「DATE」に関するクエリ全体を移動することができます

:日付制約のみをフィルタリングしている

SELECT products.id, SUM(invoice_items.amount) AS total_revenue 
FROM products 
    INNER JOIN invoice_items ON invoice_items.product = products.id 
HAVING EXISTS (SELECT 1 FROM invoices WHERE invoice_items.invoice = invoices.id 
         AND invoices.invoice_date= current_date) 
GROUP BY products.id; 
0

私が参照してください。所望の結果を有するより小さなサンプルデータが有用であろう。

問題は説明するのが少し複雑です。 left joinは日付に関係なく、すべての製品と請求書を保管しています。 invoicesへの最後の参加は、現在の日付にのみ一致する請求書を取り込みます。ただし、2つ目の表を合計しているため、一致する各行は1日に表示され(その日の請求書項目がなくても)、結果に表示されます。

ソリューション:invoice項目テーブル内の一致があるかどうかを判断するためにcaseステートメントを使用します。

 on ii.invoice = i.id and i.invoice_date >= current_date and 
     i.invoice_date < current_date + interval '1 day' 

select p.id, 
     sum(ii.amount * (case when i.id is not null then 1 end)) as total_revenue 
from products p left join 
    invoice_items ii 
    on ii.product = p.id left join 
    invoices i 
    on ii.invoice = i.id and i.invoice_date = current_date 
group by p.id; 

は、私はまた、日付の右の条件があると思われますまた、これをサブクエリとして記述すると、外部集約が保存され、問題を解決する必要があります。

select p.*, 
     (select sum(ii.amount) 
     from invoice_items ii join 
      invoices i 
      on ii.invoice = i.id and i.invoice_date >= current_date and 
       i.invoice_date < current_date + interval '1 day' 
     where ii.product = p.id 
     ) as total_revenue 
from products p; 
+0

上記の例のパフォーマンスは、メイン・セレクトのサブクエリが非常に貧弱で、テーブルがそれほど多くのレコードを超えることはないと思います。派生テーブルは、すべての製品に対して一度だけではなく、一度計算する必要があるため、より良い方法で実行する可能性があります。 @SimonWoolf。 –

+0

。 。適切な索引付けを行うと、サブクエリが最速のアプローチになる可能性があります。 –

+0

どのようにそうですか?同じ索引付けによって、派生テーブルのパフォーマンスが向上します。これは、私の経験では常にこのアプローチを凌駕します。 –

関連する問題