[英]Join Tables Conditionally Without a Subquery?
以简化形式,我们有两个表-事务表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
)上AAA444
该行。 家长可以简单地从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 |
+-------+------------+---------+-----------+
当前,我们有一个视图可以执行此操作,但是它正在使用子查询。 例如:
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');
如果可以假设缺少的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
这是要考虑的事情。 在您提供的小样本中,优化器成本为7,而原始查询为13。 不过,请对大型数据集进行尝试。
根据您的Oracle版本(应始终包含在问题中),分解式子查询声明( with
子句)中的列别名可能会起作用,也可能不会起作用; 如果您使用的是11.1或更早版本,则可能需要在分解后的子查询中移动它们。
这个想法是先做一个左连接,然后“保存”它(这是分解子查询的作用)。 然后选择item_desc
不为null
所有行; 并item_desc
为null
的行做进一步的item_desc
。
顺便说一句,在查询表中item_desc
可以为null
吗? 我以为不是(在查找表中这是不寻常的)。 如果它可以为null
,则可以很容易地对其进行修改(将i.item_id
添加到with
子句中,并使用它来确定j
哪一行去到并union all
哪个分支union all
)。
with j ( tr_id, tr_item_id, parent_lookup_type, item_desc ) as (
select t.tr_id, t.tr_item_id, substr(t.tr_item_id, 1, 3), i.item_desc
from tr t left outer join item i on t.tr_item_id = i.item_id
)
select tr_id, tr_item_id, tr_item_id as child_lookup_type, parent_lookup_type,
tr_item_id as item_id, item_desc
from j
where j.item_desc is not null
union all
select j.tr_id, j.tr_item_id, null, j.parent_lookup_type, j.parent_lookup_type,
i.item_desc
from j left outer join item i on j.parent_lookup_type = i.item_id
where j.item_desc is null
;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.