2011-09-08 6 views
1

項目の項目が「失われていて、見つかりました」という表があります。各行にはイベントの日付があります。私は、 'itemid'、 'lost date'、 'found date'の組が一致するようにテーブルを結合することを望んでいます。MySQL:日付の組を生成するための自己結合

これは一点に当てはまります:残念ながら、特定のアイテムに複数の失われたペアがある場合、それぞれの「失われた日付」はそれに続くすべての「見つかった日付」と結合されます。

まだ私と一緒ですか?

クエリが行くようなもの:

select c0.ItemId, c0.ChangeDate, c1.ChangeDate from Changes c0 
join Changes c1 on 
    c0.ItemId = c1.ItemId and c1.ChangeDate >= c0.ChangeDate 
where c0.ChangeType = 9 (lost) and c1.ChangeType = 10 (found); 
いいえ「が見つかった場合はどうImは達成することを望んにのみ、次の順序で「が見つかり日付」(またはNULLとペアに与えられた「失われた日付」のいくつかのフォームではありません

日付 'が存在する)。 Im(かなり)これは可能ですが、私はパスを見ていないことを確認します。

最初の結合にサブ選択を入れて、LIMIT 1を使用して1つのレコードしか取得できないのは不思議でしたが、これを選択のメイン部分の適切な行に結合する方法はわかりません。 MySQLはそれが存在しないと私に伝えます。けっこうだ。

答えて

3

ここにトリックが規定している「と失われたと日付を発見したとの間には、他の失われたか、見つから日付が存在しない」、または、SQL内:それは、相関サブクエリですので

SELECT c0.ItemId, c0.ChangeDate, c1.ChangeDate 
    FROM Changes AS c0 
    JOIN Changes AS c1 ON c0.ItemId = c1.ItemId AND c1.ChangeDate >= c0.ChangeDate 
WHERE c0.ChangeType = 9 -- Lost 
    AND c1.ChangeType = 10 -- Found 
    AND NOT EXISTS(SELECT * 
        FROM Changes AS c2 
        WHERE c2.ItemId = c1.ItemID 
        AND c2.ChangeType IN (9, 10) -- Lost or Found 
        AND c2.ChangeDate BETWEEN c0.ChangeDate AND c1.ChangeDate 
        AND (c2.ChangeDate != c0.ChangeDate AND c2.ChangeDate != c1.ChangeDate) 
       ); 

が、それは、クエリを遅くする傾向がありますが、正しい行が生成されるはずです。

c2の行のChangeDateが失われた日付または見つかった日付と異なるはずであることを指定して、c0およびc1行を削除した方法に関する重要な注意点があります。しかし、メインクエリでは、アイテムが失われた同じ日に見つかる可能性があります。そのような変更ID列として - - いくつかの他の列があるかもしれませんクエリで言及されていない、まだそれが代わりに使用することができます

AND c2.ChangeID NOT IN (c0.ChangeID, c1.ChangeID) 

項目が上の失われた場合は、何が起こるかを考える必要があります、 2011年6月7日に発覚し、2011年6月14日に再び失われ、2011年6月21日にのみ見つかる。それが2011年6月28日にも見つかったらどうなりますか?このような問題は、データ入力処理によって防止する必要があるため、上記の質問ではこのような問題はないと想定しています。

+0

私はこの方が読みやすいと思ったので、一緒に行った。私が変更したのは、 'ChangeType = 10'をジョインに移動してジョイントを片側にして、アイテムがまだ失われているケースを拾うことでした。 – ethrbunny

3

通常、日付のペア(スケジュールの開始/終了など)を扱う場合、アドバイスはそれらを別々の行に配置しません。それらを同じ列の2つの列に入れます。 Joe Celko's SQL Programming Styleを参照してください。

しかし、他の自己結合を検索して2つの間のChangeDateを検索することで、現在のスキーマでそれを解決できます。何も見つからない場合(つまり、外部結合のためにc2。*がヌルの場合)、c0とc1は「隣接」します。

select c0.ItemId, c0.ChangeDate, c1.ChangeDate 
from Changes c0 
inner join Changes c1 on 
    c0.ItemId = c1.ItemId and c1.ChangeDate > c0.ChangeDate 
left outer join Changes c2 on 
    c0.ItemId = c2.ItemId and c2.ChangeDate > c0.ChangeDate 
         and c2.ChangeDate < c1.ChangeDate 
         and c2.ChangeType IN (9,10) -- edit 
where c0.ChangeType = 9 (lost) and c1.ChangeType = 10 (found) 
    and c2.ItemId IS NULL; 

上記の例では、私はChangeDateが一意であると仮定し、> =>に変更しました。 ChangeDateが一意でない場合は、c0とc1の間のc2をテストするために、別の式を用意する必要があります。

+0

私が書いたものと著しく似ています。失われた日付と見つかった日付の間にChangeType 8(「電話問い合わせ」と言う)レコードがある場合は、失われたペアを拒否します。 –

+0

良い点、別の条件を結合に追加します。 –

関連する問題