1

テーブルPRODUCTSの製品レコードの重複をチェックするSQLクエリがあります。以下を除いて、ほとんどの場合、クエリは正常に機能します。

select * from products where 
product_reg_no = 'AL-NAPT' 
and (to_date('14-Aug-2001') BETWEEN to_date('27-Aug-2001') AND to_date('30-Aug-2001')
or to_date('31-Aug-2001') BETWEEN to_date('27-Aug-2001') AND to_date('30-Aug-2001'))

すべてのレコードをキャッチするためにこのクエリを作成するには、部分的または完全に重複していますか?

必要に応じて、サンプルレコードを含むテーブル構造を提供できます。

ありがとう

アップデート1

ここまたは以下のようにテーブル構造とレコードを追加しました。

create table products
(product_reg_no varchar2(32),
 start_date date,
 end_date date);


Insert into products
   (product_reg_no, START_DATE, END_DATE)
 Values
   ('AL-NAPT', TO_DATE('08/14/2012', 'MM/DD/YYYY'), TO_DATE('08/31/2012', 'MM/DD/YYYY'));
Insert into products
   (product_reg_no, START_DATE, END_DATE)
 Values
   ('AL-NAPT', TO_DATE('08/27/2012', 'MM/DD/YYYY'), TO_DATE('08/30/2012', 'MM/DD/YYYY'));
COMMIT;

2012年8月14日から2012年8月31日までの最初のレコードは、 2012年8月27日から2012年8月30日までの2番目のレコードと重複しています。では、クエリを変更して重複を取得するにはどうすればよいですか?

4

2 に答える 2

2

これは奇妙なクエリです。2001年8月14日が2001年8月27日から2001年8月30日までの間にあるかどうかを確認します。これは常に偽です。または2001年8月31日が2001年8月27日から2001年8月30日までの間にあります。これも常に偽です。したがって、あなたのwhere条項は常に偽になります。

編集:説明してくれてありがとう

SQLフィドルデモ

select   p1.product_reg_no
       , p1.start_date p1s
       , p1.end_date   p1e
       , p2.start_date p2s
       , p2.end_date   p2e
from products p1, products p2
where p1.product_reg_no = p2.product_reg_no
  and not (    p1.end_date   < p2.start_date
           and p1.start_date > p2.end_date   );

必要なのは次のシナリオです(1は最初の行を表し、2は2番目の行を表します)

1    1
 2  2

 1  1
2    2

1    1
2    2

1   1
 2   2

 1   1
2   2

あなたも振り返って、これを望まないと言うことができるということ:

1 1
   2 2

   1 1
2 2

私はあなたもこれが欲しいと思いました

1 1
  2 2

  1 1
2 2

条項は別のWHERE方法で書くこともできます

not (    p1.end_date   < p2.start_date and p1.start_date > p2.end_date   )

と同じです

        p1.end_date   >= p2.start_date or p1.start_date <= p2.end_date   

私が昔学校でそれを持っていたとき、それはド・モルガンの法則と呼ばれていたと思います。

2行を超える場合はどうなるかを考える必要があります。

于 2012-10-01T05:19:02.010 に答える
2

2つの日付範囲が重複しているかどうかを確認するを参照してください。

おそらく、<=の代わりにを使用して、次の、またはそのマイナーバリアントを評価する必要があります。<

Start1 < End2 AND Start2 < End1

単一のテーブルで作業しているため、自己結合が必要です。

SELECT p1.*, p2.*
  FROM products p1
  JOIN products p2
    ON p1.product_reg_no != p2.product_reg_no
   AND p1.start < p2.end
   AND p2.start < p1.end;

等しくない条件は、それ自体とペアになっているレコードを取得しないことを保証します(ただし、<条件はそれを保証しますが、を使用した場合は<=、等しくない条件を使用することをお勧めします。

これにより、製品のペアごとに2つの行が生成されます(1つの行はProductAasp1とProductBas、p2もう1つの行はProductBasp1とProductAas p2)。これを防ぐには、をまたはに変更!=します。<>


また、サンプルデータを詳しく見ると、登録番号が一致し、日付が重複している行に非常に興味があるかもしれません。その場合、あなたは私の悩みを無視して、!=そして<または、結局>、状態を置き換えることができ=ます。

SELECT p1.*, p2.*
  FROM products p1
  JOIN products p2
    ON p1.product_reg_no = p2.product_reg_no
   AND p1.start < p2.end
   AND p2.start < p1.end;

SQL Fiddle(未保存)は、これが機能することを示しています。

SELECT p1.product_reg_no p1_reg, p1.start_date p1_start, p1.end_date p1_end,
       p2.product_reg_no p2_reg, p2.start_date p2_start, p2.end_date p2_end
  FROM products p1
  JOIN products p2
    ON p1.product_reg_no = p2.product_reg_no
   AND p1.start_date < p2.end_date
   AND p2.start_date < p1.end_date
 WHERE (p1.start_date != p2.start_date OR p1.end_date != p2.end_date);

WHERE句は、それ自体に結合されている行を削除します。SELECTリスト内の重複する列名を削除すると、すべてのデータを表示できます。行を追加しました:

INSERT INTO products (product_reg_no, start_date, end_date)
VALUES ('AL-NAPT', TO_DATE('08/27/2011', 'MM/DD/YYYY'), TO_DATE('08/30/2011', 'MM/DD/YYYY'));

これは選択されませんでした—重複しないエントリを拒否することを示しています。

二重行を削除したい場合は、別の派手な基準を追加する必要があります。

SELECT p1.product_reg_no p1_reg, p1.start_date p1_start, p1.end_date p1_end,
       p2.product_reg_no p2_reg, p2.start_date p2_start, p2.end_date p2_end
  FROM products p1
  JOIN products p2
    ON p1.product_reg_no = p2.product_reg_no
   AND p1.start_date < p2.end_date
   AND p2.start_date < p1.end_date
 WHERE (p1.start_date != p2.start_date OR p1.end_date != p2.end_date)
   AND (p1.start_date < p2.start_date OR
       (p1.start_date = p2.start_date AND p1.end_date < p2.end_date));
于 2012-10-01T06:16:49.563 に答える