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正在每个连接上执行?这是如何执行的?
由于
答案 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;