1

製品

product_id  product_serial_number   product_status
1           X123                    PENDING
1           X123                    PROCESSED
2           X345                    PENDING
3           X678                    PENDING
4           Y890                    PENDING
4           Y890                    PROCESSED

上の表は、製品のステータスとその履歴を示しています。出力が次のようになるレポートを作成する必要があります。

product_id  status
1           UPDATE
2           NEW
3           NEW
4           UPDATE

つまり、製品が以前に処理された場合 (例: 製品 1 と 4)、そのステータスは UPDATE です。それ以外の場合、そのステータスは NEW です。

私はこのクエリを思いつきましたが、そのパフォーマンスに満足していません:

select product_id, 'UPDATE'
from products p1
where product_id in (select product_id from products p2 where p2.product_status='PROCESSED' and p2.product_status='ARCHIVED')
Union
select product_id, 'NEW'
from products p1
where product_id not in (select product_id from products p2 where p2.product_status='PROCESSED' and p2.product_status='ARCHIVED')

別の方法として、テーブルをそれ自体に結合することもできます。

select p1.product_id, decode(p2.product_id, null, 'NEW','UPDATE')
from products p1, products p2
where p1.product_id=p2.product_id(+)
and p1.product_serial_number=p2.serial_number(+)
and p2.product_status(+) = 'PROCESSED'

いずれかのクエリが大規模なデータ セットに対して実行される場合、パフォーマンスはあまり良くありません。最高のパフォーマンスを得るために、上記のクエリをどのように改善 (または完全に変更) できますか?

4

4 に答える 4

3

使ってみましたGROUP BYか?

SELECT product_id, (CASE WHEN COUNT(*) = 1 THEN 'NEW' ELSE 'UPDATED' END) status
FROM products
WHERE product_status <> 'ARCHIVED'
GROUP BY product_id

GROUP BY 他の集計関数を確認してください。

編集

Case 式の構文の問題を修正しました。申し訳ありません。

于 2013-03-10T03:50:14.540 に答える
1

これを試して

with CTE as
(
   select product_id, decode(product_status,'PROCESSED','UPDATE','NEW') status,
   row_number() over (partition by product_id
   order by decode(product_status,'PROCESSED','UPDATE','NEW') desc) rnum
   from products p1
)
select * from cte where rnum = 1
于 2013-03-10T04:54:58.987 に答える
1

UNION の見過ごされがちな MINUS と INTERSECT を使用すると、速度が向上する場合があります。

PENDING 行と PROCESSED 行があるすべての製品:

SELECT product_id FROM Products WHERE product_status = 'PENDING'
INTERSECT SELECT product_id FROM Products WHERE product_status = 'PROCESSED'

PENDING 行があり、PROCESSED 行がないすべての製品:

SELECT product_id FROM Products WHERE product_status = 'PENDING'
MINUS SELECT product_id FROM Products WHERE product_status = 'PROCESSED'

それらをまとめます (そして NEW/UPDATE を追加します):

SELECT product_id, 'NEW' FROM (
   SELECT product_id FROM Products WHERE product_status = 'PENDING'
   MINUS SELECT product_id FROM Products WHERE product_status = 'PROCESSED')
UNION
SELECT product_id, 'UPDATE' FROM (
  SELECT product_id FROM Products WHERE product_status = 'PENDING'
  INTERSECT SELECT product_id FROM Products WHERE product_status = 'PROCESSED')

大きなテーブルの場合、行の少なくとも 2/3 が関係するため、クエリが超高速になることはありません。

このクエリを頻繁に実行する予定がある場合は、 のインデックスも考慮する必要がありますproduct_status

于 2013-03-10T04:33:33.080 に答える
1

以前の回答に加えて (INTERSECT anв MINUS に関する回答が気に入っています)。

フィールド 'product_status' の可能な値が非常に少ない場合、通常のインデックス (B ツリーに基づく) はうまく機能しません。このフィールドではビットマップ インデックスを使用する必要があります。 Oracle Bitmap Index Techniques CREATE INDEX in Oracle Docs - search for bitmap

于 2013-03-11T09:20:25.447 に答える