web-dev-qa-db-ja.com

外部自己結合フィルターとサブクエリ

チケットに関する情報を格納したテーブルがあります。チケットが販売されたときのレコードと、チケットが使用されたときのレコードがあります。 TransTypeと呼ばれる列があり、これは「販売済み」または「使用済み」のいずれかに設定されて、どちらであるかを示します。テーブルには他の列があり、それらのいくつかは、それが販売の場合は値を含みますが、それが使用される場合は含まれません。逆も同様です。テーブルは、実際にはデータウェアハウススタイルのファクトテーブルです。

他にも、売上と中古の時間差を計算しているので、同じレコードの両方のイベントのタイムスタンプを計算できるように、チケットごとに1つのレコードを取得するためにテーブルを結合しています。

私はすべての販売済みチケットを含める必要があるので、外部結合はそれを解決する必要があります。

最初にこのクエリを実行しました

select x.* 
from factI as x
left join factI as y on x.tickedId = y.tickedId
where x.TransType = 'sold'
and y.TransType = 'used'

実行すると、フィルターx.TransType = 'sold'が機能せず、クエリはTransTypeに関係なく、事実上すべてのレコードの結果を返します。内部結合を使用すると、これは機能しますが、使用されていないチケットを返すことはできません。

クエリを変更して、正しい結果が得られるクエリに変更しました。

select * from (
   select * from factI where TransType = 'sold'
) as x
left join (
   select * from factI where TransType = 'used'
) as y on x.ticketId = y.ticketId

外部(左)結合を使用すると、最初のクエリのwhere句が正しくフィルタリングされないのはなぜですか?

4
bjorsig

正しいテーブルを使用するinner join条件がwhere句にあるため、最初のクエリはy.TransType = 'used'として機能します。

2番目のクエリは、その条件をon句に移動するだけで、派生テーブルなしで書き換えることができます。

select x.*, y.*
from factI as x
left join factI as y on  x.tickedId = y.tickedId
                     and y.TransType = 'used'
where x.TransType = 'sold' ;
10
ypercubeᵀᴹ

最初のクエリのwhere句では、結果をy.TransType = 'used'の結果に制限しています。 y.TransTypeがnull(他のチケットが存在しない場所)である結果を破棄するため、これにより左結合が内部結合に変わります。

これを簡単に修正するには、次のようにその条件をon句に移動します。

select x.* 
from factI as x
left join factI as y on x.tickedId = y.tickedId
    and y.TransType = 'used' -- moved the condition to the on clause
where x.TransType = 'sold'

原則として、外部結合列の条件はon句ではなくwhere句に保持します。それ以外の場合は、nullを確認する必要があります。

select x.* 
from factI as x
left join factI as y on x.tickedId = y.tickedId
where x.TransType = 'sold'
and (y.TransType = 'used' or y.TransType is null)
1
user2023861