我正试图获得每个月收取笼子的租金率。以下是如何获得它的逻辑:
cage
表中定义了费率,请使用该表的外键链接到rate
表。rack
表中定义了费率,请使用该表的外键链接到rate
表。room
表中定义了费率,请使用该表的外键链接到rate
表。false
返回$0.00
(免费租金)。所以这里有一些表格供您直观地了解我目前的情况。
id cage_number rate_id rack_id room_id
----------------------------------------------------
1 FG-12 600 1 1
2 FG-13 600 1 1
3 FG-14 NULL 2 1
4 FG-15 NULL 2 3
id rack_number rate_id
-----------------------------
1 BN-806 700
2 BN-971 NULL
id room_number rate_id
-----------------------------
1 UM-100 800
2 UM-150 900
3 UM-200 NULL
id rate_id effective_on rate_value
------------------------------------------
1 600 01-Apr-2015 0.67
2 600 01-Oct-2016 0.80
3 700 01-Jan-2016 0.56
4 800 01-Jul-2012 0.61
5 800 01-Dec-2015 0.85
6 900 01-Feb-2015 0.75
7 900 01-Mar-2015 0.79
8 900 01-Apr-2015 0.90
因为您可以看到每个rate_id
有多行,因为价格会不时变化。我已经通过查看rate_id
字段来查询每个effective_on
的正确率:
SELECT *
FROM rates r
WHERE r.id = (
SELECT MAX(rr.id) AS curr
FROM rates rr
WHERE rr.rent_id = r.rent_id
AND TRUNC(rr.effective_on) <= TRUNC(sysdate)
)
让我们回到我的主要问题。我需要使用位于3个不同表格的rate
加入rate_id
表。
我目前的方法是使用3个不同的别名加入rate
表3次,但由于速率可能有多行,所有3个实例每个都可能有多行导致大量不需要的行行。
FROM cages c
LEFT JOIN racks rk ON rk.id = c.rack_id
LEFT JOIN rooms rm ON rm.id = c.room_id
LEFT JOIN rates cr ON cr.rate_id = c.rate_id
LEFT JOIN rates rkr ON rkr.rate_id = rk.rate_id
LEFT JOIN rates rmr ON rmr.rate_id = rm.rate_id
我在考虑一个解决方案,我只需要加入rate
表一次来解决这个问题,但是当我尝试它时 - 它失败了(正如预期的那样)。
FROM cages c
LEFT JOIN racks rk ON rk.id = c.rack_id
LEFT JOIN rooms rm ON rm.id = c.room_id
CASE
WHEN c.rate_id IS NOT NULL
THEN LEFT JOIN rates r ON r.rate_id = c.rate_id
WHEN rk.rate_id IS NOT NULL
THEN LEFT JOIN rates r ON r.rate_id = rk.rate_id
WHEN rm.rate_id IS NOT NULL
THEN LEFT JOIN rates r ON r.rate_id = rm.rate_id
END
答案 0 :(得分:1)
您不能使用案例表达式来决定使用哪个加入条件,但您可以在条件的右侧使用案例表达式来决定您的&# 39;重新尝试将费率表的ID与:
相匹配FROM cages c
LEFT JOIN racks rk ON rk.id = c.rack_id
LEFT JOIN rooms rm ON rm.id = c.room_id
LEFT JOIN rates r ON r.rate_id =
CASE
WHEN c.rate_id IS NOT NULL THEN c.rate_id
WHEN rk.rate_id IS NOT NULL THEN rk.rate_id
WHEN rm.rate_id IS NOT NULL THEN rm.rate_id
END
但是对于费率表上的外连接条件使用coalesce()
更简单:
LEFT JOIN rates r ON r.rate_id = COALESCE(c.rate_id, rk.rate_id, rm.rate_id)
或者更有用的是针对费率表的子查询,该表查找每个ID的最新费率:
select cages.cage_number,
rates.rate_id as rate_id,
nvl(rates.rate_value, 0)
from cages
left join racks on racks.id = cages.rack_id
left join rooms on rooms.id = cages.room_id
left join (
select rate_id,
max(rate_value) keep (dense_rank last order by effective_on) as rate_value
from rates
where effective_on <= trunc(sysdate)
group by rate_id
) rates on rates.rate_id = coalesce(cages.rate_id, racks.rate_id, rooms.rate_id);
CAGE_ RATE_ID COALESCE(RATES.RATE_VALUE,0)
----- ---------- ----------------------------
FG-13 600 .8
FG-12 600 .8
FG-14 800 .85
FG-15 0
子查询忽略了将来开始的速度,正如您已经在做的那样;并使用keep dense_rank last
to avoid the self-join。
然后将该子查询用作内联视图(为简单起见,别名为&#39; rate&#39;)。加入条件使用coalesce来加入笼子的费率ID(如果已设置);那么机架ID;然后是房间ID。最后,如果根本没有匹配,那么另一个合并将最终选择的值设置为零。
正如@mathguy指出的那样,这最终可能会做一些不必要的工作 - 如果笼子里有一个费率ID,那么看看那个笼子的其他桌子是没有意义的。取决于数据的选择性可能无关紧要,但如果它确实影响性能,您可以考虑修改外连接条件以消除其中的一些:
from cages
left join racks on racks.id = cages.rack_id
and cages.rate_id is null
left join rooms on rooms.id = cages.room_id
and cages.rate_id is null
and racks.rate_id is null
left join (
...
答案 1 :(得分:1)
这是为每个笼子获得正确rate_id
的不同方法。根据您在不同表中的null
个数量,它可能比在整个表上执行左连接更有效(更快)。我们的想法是在rate_id
表不为空时从cages
表中收集rates
,并且只有当它为空才能加入到机架表时,并且只有当它不起作用时才加入只有剩余的行到房间表。
我没有展示如何将此“连接”到with
prep ( id, cage_number, rate_id, room_id ) as (
select c.id, c.cage_number, rk.rate_id, c.room_id
from cages c left outer join racks rk on c.rack_id = rk.id
where c.rate_id is null
)
select id, cage_number, rate_id
from cages
where rate_id is not null
union all
select id, cage_number, rate_id
from prep
where rate_id is not null
union all
select p.id, p.cage_number, rm.rate_id
from prep p left outer join rooms rm on p.room_id = rm.id
where p.rate_id is null
;
表格 - 在Alex的回答中这两种方法都可以。 (我会再次使用第二个版本来提高效率。)
clickable