在Oracle的where子句中与子查询合并

时间:2016-09-05 18:23:58

标签: oracle subquery

HY,

我在Oracle中有下一个sql查询:

想象一下,我有一张桌子" items"用" id"和"名称"字段和其他表" 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) 

我正在使用的查询是这样的,但我不知道它是如何工作的,因为coalesce正在每个连接上执行?这是如何执行的?

由于

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分: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()参数中的第一个非空值才是保留的值。实际情况是,重新编写查询可能更有效,因此您不需要它们。

还有其他方法可以写这个。这些天最常见的似乎是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;