2016-09-05 3 views
1

Hy,сливаться с подзапроса в ИНЕКЕ в Oracle

У меня есть следующий запрос SQL в Oracle:

Imagine У меня есть таблица «пунктов» с «ид» и поля «имя» и другие table "prices_items", которые имеют три поля с именем «id, itemId, category». Категория может иметь три значения: «1,2,3». Поэтому запрос, который мне нужно сделать, это получить цену элемента из таблицы «prices_items», но элемент может иметь до трех цен из-за поля категории. Так, в 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

The 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() сохраняется. Реальность заключается в том, что, вероятно, более эффективно переписывать запрос, чтобы он вам не нужен.

Есть и другие способы написать это. Тот, который является самым распространенным в эти дни, кажется, row_number() подход:

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-конкретное решение:

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 Setup:

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 
Смежные вопросы