2017-11-01 4 views
0

同じ結果を返すと予想される同じクエリの2つのバージョンがありますが、結果は異なります。PostgreSQLのクエリ配置により異なる結果が発生する

クエリ1:

select * from erp_data.invoices i 
left join 
(select * from erp_data.invoice_extra_data where data_key = 'job_number') d 
using(invoice_id) 
where customer_no = '6357' and (data_key = 'job_number' or data_key is null) 
and (customer_purchase_order_no ilike '%newtown%' or customer_purchase_order_no ilike '%newtown%' or customer_purchase_order_no ilike '%newton%') 
and (order_date >= '2017-09-01' and order_date < '2017-11-01') 

クエリ2:

select * from erp_data.invoices i 
left join erp_data.invoice_extra_data d 
using(invoice_id) 
where customer_no = '6357' and (data_key = 'job_number' or data_key is null) 
and (customer_purchase_order_no ilike '%newtown%' or customer_purchase_order_no ilike '%newtown%' or customer_purchase_order_no ilike '%newton%') 
and (order_date >= '2017-09-01' and order_date < '2017-11-01') 

これは、PostgreSQLは最初に参加しないように見え、その後、参加にどこ原因が適用されます。 invoice_extra_dataテーブルにインボイステーブルのすべてのアイテムにSOMETHINGがあるため、すべての請求書にdata_key = 'job_number'というものがあるわけではないので、2つのクエリが異なる結果を返します。

具体的には、data_key = 'job_number'のinvoice_extra_dataテーブルにエントリを持たない請求書は、2番目のクエリで除外されます。 「左の結合のためにそのような請求書を表示する」または「それが失敗するので、そのような請求書を拒否する」という「期待される結果」を解釈することができます。

postgresqlは、クエリのwhere部分にフィルタを適用する前に常にjoinを実行しますか?

+0

EXPLAINの出力を見ましたか? – fvu

+0

"EXPLAIN"は、両方のクエリで同じように見える結果を生成しました。私はクエリブラウザで "EXPLAIN"を実行し、作成した画像を見ました - 私は説明から生のテキストを見ていませんでした。 – zelinka

+0

2つのテーブルエイリアス、 'd'と' i'を導入しました。さて、**それらを使用してください**。 – wildplasser

答えて

1

請求書テーブル内のすべての項目が にinvoice_extra_dataテーブルを何かを持っていますが、すべての請求書が data_key =「job_number」

で何かを持っていないので、あなたが、レコードを持っているとしましょうので、私はこれを言いますerp_data.invoice_extra_data where data_key = 'other_id'にあります。

最初のクエリでは、このレコードはWHEREステートメントのために最初の左結合中に除外されます。次に、値が 'job_number'かNULLかを確認し、除外されているためNULLになっているかどうかを確認します。それは通過し、含まれます。

2番目のクエリでは、WHEREステートメントがないため、このレコードは最初の左結合の際に除外されません。その後、値が 'job_number'かNULLかをチェックし、除外されていないため 'other_id'です。それは今や合格しないし、含まれないだろう。

SELECT * 
FROM erp_data.invoices i 
    LEFT JOIN erp_data.invoice_extra_data d ON i.invoice_id=d.invoice_id 
     AND data_key = 'job_number' 
WHERE customer_no = '6357' 
    AND (customer_purchase_order_no ilike '%newtown%' 
      OR customer_purchase_order_no ilike '%newtown%' 
      OR customer_purchase_order_no ilike '%newton%') 
    AND order_date >= '2017-09-01' 
    AND order_date < '2017-11-01' 
0

Q:あなたはそれを単純化したい場合

あなたの最初のクエリは、のように書くこともできPostgreSQLは常に、クエリの どこの部分にフィルタを適用する前に、参加しないん?

はい、The WHERE clauseに記載のとおり

FROM句の処理が行われた後、 由来仮想テーブルの各行は検索条件と照合されます。条件の結果が の場合、行は出力表の に保持されます(結果がfalseまたはnullの場合)。これは破棄されます。

関連する問題