在简化形式中,我们有两个表 - 事务表TR和查找表ITEM:
表项目:
+---------+-----------+
| ITEM_ID | ITEM_DESC |
+---------+-----------+
| AAA | parent |
| AAA111 | child abc |
| AAA222 | child xyz |
+---------+-----------+
表TR:
+-------+------------+
| TR_ID | TR_ITEM_ID |
+-------+------------+
| 1 | AAA |
| 2 | AAA111 |
| 3 | AAA222 |
| 4 | AAA333 |
| 5 | AAA444 |
+-------+------------+
当我们连接这两个表时,如果查找表中不存在TR_ITEM_ID
(例如AAA333
或AAA444
),则必须在“父”项上连接此行(即AAA
)。父母可以简单地从ID的前三个字母推断出来。所以期望的结果应该是:
+-------+------------+---------+-----------+
| TR_ID | TR_ITEM_ID | ITEM_ID | ITEM_DESC |
+-------+------------+---------+-----------+
| 1 | AAA | AAA | parent |
| 2 | AAA111 | AAA111 | child abc |
| 3 | AAA222 | AAA222 | child xyz |
| 4 | AAA333 | AAA | parent |
| 5 | AAA444 | AAA | parent |
+-------+------------+---------+-----------+
目前我们有一个视图可以做到这一点,但它正在使用子查询。 e.g:
select * from (
select TR.*,
(select ITEM.ITEM_ID from ITEM where TR.TR_ITEM_ID = ITEM.ITEM_ID) CHILD_LOOKUP_TYPE,
(select ITEM.ITEM_ID from ITEM where substr(TR.TR_ITEM_ID,1,3) = ITEM.ITEM_ID) PARENT_LOOKUP_TYPE
from TR
) f left outer join ITEM on ITEM.ITEM_ID =
case
when f.CHILD_LOOKUP_TYPE is not null then f.CHILD_LOOKUP_TYPE
when f.PARENT_LOOKUP_TYPE is not null then f.PARENT_LOOKUP_TYPE
end
order by TR_ITEM_ID;
问题在于,如果我们没有子查询,那么视图的执行速度会更快(实际视图中还有其他连接,但总的来说我们估计它的运行速度接近10倍)。所以问题是,有没有办法在没有子查询的情况下重写上面的视图?或任何其他建议,以使联接更有效?
以下是我们的一些限制,以防这些限制:
ITEM_ID
,因为我们无法修改客户数据库中的历史数据。AAA333
),因此“已解决”的值将无效。这是一些快速的SQL:
CREATE TABLE ITEM (
ITEM_ID VARCHAR2(20 BYTE),
ITEM_DESC VARCHAR2(20 BYTE)
);
Insert into ITEM (ITEM_ID,ITEM_DESC) values ('AAA','parent');
Insert into ITEM (ITEM_ID,ITEM_DESC) values ('AAA111','child abc');
Insert into ITEM (ITEM_ID,ITEM_DESC) values ('AAA222','child xyz');
CREATE TABLE TR (
TR_ID NUMBER,
TR_ITEM_ID VARCHAR2(20 BYTE)
);
Insert into TR (TR_ID,TR_ITEM_ID) values (1,'AAA');
Insert into TR (TR_ID,TR_ITEM_ID) values (2,'AAA111');
Insert into TR (TR_ID,TR_ITEM_ID) values (3,'AAA222');
Insert into TR (TR_ID,TR_ITEM_ID) values (4,'AAA333');
Insert into TR (TR_ID,TR_ITEM_ID) values (5,'AAA444');
答案 0 :(得分:0)
如果可以假设缺少的item_id的item_desc应始终为parent
,则这将是一个left join
的简单查询。
select
tr.tr_id
,tr.tr_item_id
,coalesce(i.item_id,substr(tr.tr_item_id,1,3)) as item_id
,coalesce(i.item_desc,(select item_desc from item where substring(tr.tr_item_id,1,3)=item_id)) as item_desc
from tr
left join item i on tr.tr_item_id=i.item_id
答案 1 :(得分:0)
这是需要考虑的事情。在您提供的小样本上,优化器成本为7,而原始查询为13。不过在你的大数据集上尝试一下。
根据您的Oracle版本(您应该始终包含您的问题),factored子查询声明(with
子句)中的列别名可能有效,也可能无效;如果您在11.1或之前,则可能需要在因子子查询中移动它们。
我们的想法是首先进行左连接,然后“保存”它(这是一个因子子查询所做的事情)。然后选择item_desc
不是null
的所有行;并为null
的{{1}}行进行进一步的连接。
顺便说一句,查找表中的item_desc
可以item_desc
吗?我没想到(在查询表中会不寻常);如果可以为null
,则可以轻松调整(将null
添加到i.item_id
子句,并使用它来确定来自{{1}的哪一行}转到with
)的哪个分支。
j