2016-09-05 11 views
1
で句

のHy、は、私はOracleで次のSQLクエリを持っているところオラクル

のサブクエリと合体:

は、私は、「ID」と「名前」フィールドやその他の持つテーブル「アイテム」を持っている想像してみてテーブル "prices_items"には、 "id、itemId、category"という3つのフィールドがあります。カテゴリには3つの値、「1,2,3」があります。だから私がする必要があるクエリは、 "price_items"テーブルのアイテムの価格を得ることですが、アイテムはカテゴリフィールドのために3つの価格まで持つことができます。だから、priotiryの順序では、私はカテゴリ1を持っているアイテムの価格を取得する必要があります、アイテムがこのカテゴリを持っていない場合は、カテゴリ2の価格を見つける必要があります。

from items 
left join prices_items on prices_items.itemId = items.itemId 
where prices_items.id = coalesce(select id 
           from prices_items 
           where itemId= items.itemId and category=1, 
           select id 
           from prices_items 
           where itemId= items.itemId and category=2, 
           select id 
           from prices_items 
           where itemId= items.itemId and category=3) 

私が使用しているクエリは、このようなものですが、私は合体がそれぞれ上で実行されているので、その作業に参加する方法を知りません?。これはどのように実行されていますか?

おかげ

+0

ようにクエリが動作しますか?何が問題ですか? –

+0

このドキュメントのリンクは - [coalesce](https://docs.oracle.com/cd/B28359_01/server.111/b28286/functions023.htm) - help? – Plirkee

+0

合体が一度だけ実行されると思いました。私が言っていることは、融合が複数回実行されるということですか? – user3254515

答えて

1

coalesce()が記載されているカテゴリの順序で見つかった最初のprices_items.idを維持しようとしています。個々のサブクエリの代わりに、この方法で書くことができ、おそらくより良い計画が得られます。

select ... 
from items inner join prices_items on prices_items.itemId = items.itemId 
where prices_items.category = (
    select min(pi2.category) from prices_items pi2 
    where pi2.itemId = items.itemId 
); 

カテゴリの優先順位は、あなたがcase表現でそれを扱うことができる昇順に従うことが起こらない場合は、次の

select ... 
from items inner join prices_items on prices_items.itemId = items.itemId 
where 
    case prices_items.category 
     when 2 then 1 
     when 3 then 2 
     when 1 then 3 
    end = (
     select 
      min(case pi2.category 
       when 2 then 1 
       when 3 then 2 
       when 1 then 3 
      end) 
     from prices_items pi2 
     where pi2.itemId = items.itemId 
    ); 

限り、あなたの現在のクエリが実際にそれを実行している方法かもしれないとして、あるいはすべてのサブクエリ結果を実現していない可能性があります。最終結果の観点から、実際に知る必要があるのは、coalesce()引数の最初の非NULL値だけが保持されていることです。現実には、クエリーを書き直すほうがおそらく効率的です。

これを書き込む他の方法があります。このごろ最も一般的です1はrow_number()アプローチのようだ:

select * 
from 
    items inner join 
    (
     select itemId, min(price) keep (dense_rank first order by category) as price 
     from prices_items 
     group by itemId 
    ) pi on pi.itemId = items.itemId; 
2

Oracleのセットアップ

with data as (
    select *, 
     row_number() over (partition by pi.itemId order by pi.category) as rn 
    from items inner join prices_items pi on pi.itemId = items.itemId 
) 
select ... 
from data 
where rn = 1; 

ここで別のOracle固有のソリューションです

CREATE TABLE items (
    itemid NUMBER PRIMARY KEY, 
    name VARCHAR2(20) 
); 

CREATE TABLE prices_items (
    itemId NUMBER REFERENCES items (itemid), 
    category INT, 
    price NUMBER, 
    CHECK (category IN (1, 2, 3)), 
    PRIMARY KEY (itemid, category) 
); 

INSERT INTO items 
SELECT 1, 'A' FROM DUAL UNION ALL 
SELECT 2, 'B' FROM DUAL UNION ALL 
SELECT 3, 'C' FROM DUAL; 

INSERT INTO prices_items 
SELECT 1, 1, 32.5 FROM DUAL UNION ALL 
SELECT 1, 2, 23.9 FROM DUAL UNION ALL 
SELECT 1, 3, 19.99 FROM DUAL UNION ALL 
SELECT 2, 1, 42.42 FROM DUAL UNION ALL 
SELECT 2, 3, 99.99 FROM DUAL UNION ALL 
SELECT 3, 2, 0.02 FROM DUAL UNION ALL 
SELECT 3, 3, 10 FROM DUAL; 

クエリ

SELECT i.itemid, 
     name, 
     category, 
     price 
FROM items i 
     INNER JOIN 
     (SELECT itemid, 
       MIN(category) AS category, 
       MAX(price) KEEP (DENSE_RANK FIRST ORDER BY category) AS price 
     FROM prices_items 
     GROUP BY itemid 
     ) p 
     ON (i.itemid = p.itemid); 

出力

ID NAME CATEGORY PRICE 
-- ---- -------- ----- 
1 A 1  32.50 
2 B 1  42.42 
3 C 2   0.02 
関連する問題