我正在尝试重写下面的查询,用内连接替换'IN'子句
select * from employee_rec er
inner join ed_claim_recd ed on er.ssn=ed.insssn and substr(er.group_rec_key,1,10) = substr(er.group_rec_key,1,10)
and ed.claim in (select claimno from cd_claim_recd cd where cd.closedt is not null and cd.closedt != '0000000' and cd.closedt >= '2130101')
and ed.insssn in (select er1.ssn from employee_rec er1 where er1.status != 'ACTIV' and trim(ER1.CLAIMNO) is null)
and er.sysind not in ('ABC,'BCD')
以下是我可以提出的结果,但结果与之前的查询不同
select * from employee_rec er
inner join ed_claim_recd ed on er.ssn = ed.insssn and substr(er.group_rec_key, 1, 10) = substr(er.group_rec_key, 1, 10)
inner join (select claimno from cd_claim_recd cd where cd.closedt is not null and cd.closedt != '0000000' and cd.closedt >= '2130101') cr on ed.claim = cr.claimno
inner join (
select insssn from ed_claim_recd ed2
inner join (
select ssn from employee_rec er1
where
er1.status != 'ACTIV'
and trim(ER1.CLAIMNO) is null
) er2 on ed2.insssn = er2.ssn
) ed3 on ed.insssn = ed3.insssn
and er.sysind not in ('ABC', 'BCD')
这是重写查询的正确方法还是我太过分了?另外,它是一种有效的方法来重写查询以将“IN”替换为“INNER JOIN”吗?
答案 0 :(得分:5)
IN
子查询和INNER JOIN
的工作方式不同。 Join将从一个表中为每个连接键输出具有来自连接表的相同键的所有行。因此,如果连接表中的连接键不唯一,则Join可以复制行。 IN
子查询不会重复行。
例如,如果在cr
加入子查询
inner join (select claimno from cd_claim_recd cd where cd.closedt is not null and cd.closedt != '0000000' and cd.closedt >= '2130101') cr on ed.claim = cr.claimno
claimno
不是唯一的,然后匹配claimno
的已加入行将被复制。这是很正常的加入行为。
要避免此类重复,请通过添加DISTINCT
,row_number()
过滤器,group by
等确保加入密钥是唯一的:
inner join (select DISTINCT claimno from cd_claim_recd cd where cd.closedt is not null and cd.closedt != '0000000' and cd.closedt >= '2130101') cr on ed.claim = cr.claimno
其他此类连接也一样。
在这种情况下,IN
和Join
的结果应该相同。
顺便说一句,你不需要所有这些条件:
where cd.closedt is not null and cd.closedt != '0000000' and cd.closedt >= '2130101'
因为' 2130101'大于' 0000000'如果cd.closedt> =' 2130101'它不能为NULL。 cd.closedt >= '2130101'
已经足够了。
找到了另一个可能的问题:
and trim(ER1.CLAIMNO) is null
在Hive中(你用@hive标签标记了你的问题)空字符串和null是两个不同的东西。
在Hive中 ('' is not NULL) = true
。
我建议将其替换为and (ER.CLAIMNO is null or trim(ER1.CLAIMNO)='')
空字符串是Hive中的正常值,这就是空字符串参与连接的原因。如果您不需要将它们连接起来,请在加入前转换为NULL或过滤它们。
ed3
子查询包含冗余连接,它与原始IN
子查询不同。
也许还有其他问题。逐个测试所有连接以找到所有连接
答案 1 :(得分:1)
我这样做(未经测试):
select er.*, ed.*
from employee_rec er
join ed_claim_recd ed
on ed.insssn = er.ssn
and substr(ed.group_rec_key,1,10) /* was er.group_rec_key */ = substr(er.group_rec_key,1,10)
join cd_claim_recd cd
on cd.claimno = ed.claim
join employee_rec er1
on er1.ssn = ed.insssn
where er.sysind not in ('ABC', 'BCD')
-- and cd.closedt is not null -- redundant
-- and cd.closedt != '0000000' -- redundant
and cd.closedt >= '2130101'
and er1.status != 'ACTIV'
and trim(er1.claimno) is null
如果cd_claim_recd.claimno
和employee_rec.ssn
而非唯一键,那么您可能需要一些重复数据删除逻辑。
答案 2 :(得分:1)
以下内容消除了IN
:
select er.*, ed.*
from employee_rec er
inner join ed_claim_recd ed
on er.ssn=ed.insssn and
substr(ed.group_rec_key,1,10) = substr(er.group_rec_key,1,10)
INNER JOIN (select claimno
from cd_claim_recd cd
where cd.closedt is not null and
cd.closedt != '0000000' and
cd.closedt >= '2130101') j1
ON j1.CLAIMNO = ed.claim
INNER JOIN (select er1.ssn from employee_rec er1
where er1.status != 'ACTIV' and
trim(ER1.CLAIMNO) is null) and
er.sysind not in ('ABC,'BCD')) j2
ON j2.SSN = ed.insssn
正如@GordonLinoff正确地指出的那样,这可能根本不会影响性能。
祝你好运。
答案 3 :(得分:1)
在hive的情况下,我们需要用INNER join替换IN clasue。您可以按如下方式重写上述查询。我认为我们不需要两次加入 employee_rec 表来获得结果。
select er.*,ed.* from employee_rec er
inner join
ed_claim_recd ed
on er.ssn = ed.insssn
inner join cd_claim_recd cd
on ed.claim = cd.claimno
where cd.closedt is not null
and cd.closedt != '0000000'
and cd.closedt >= '2130101'
and er.status != 'ACTIV' and trim(er.CLAIMNO) is null
and er.sysind not in ('ABC,'BCD')
正如我们消除一个连接条件一样,这是实现结果的紧凑而有效的方法。由于我不知道数据,我没有测试过。如果您有重复的CLAIMS和SSN,那么您需要处理它。正如@leftjoin所提到的,您可以通过消除CLOSEDT上的冗余条件来进一步提高性能