チケットに関する情報を格納したテーブルがあります。チケットが販売されたときのレコードと、チケットが使用されたときのレコードがあります。 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句が正しくフィルタリングされないのはなぜですか?
正しいテーブルを使用する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' ;
最初のクエリの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)