问题
I have come across the following legacy PL/SQL and find the outer joins against scalar constants somewhat confusing. First of all, can someone please confirm that my attempt to convert this to ANSI is correct.
LEGACY CODE:
cursor c1item (c1item_iel_id number) is
select
`<columns>`
from iel_item iit, iel_item_property iip
where iit.iit_change_type = 'I'
and iip.iip_change_type (+) = 'I'
and iip.it_id (+) = iit.it_id
and iit.iel_id = c1item_iel_id
and iip.iel_id (+) = c1item_iel_id;
ANSI CODE
cursor c1item (c1item_iel_id number) is
select
`<columns>`
from iel_item iit
left outer join iel_item_property iip
on iip.it_id = iit.it_id
and iit.iit_change_type = 'I'
and iip.iip_change_type = 'I'
and iit.iel_id = c1item_iel_id
and iip.iel_id = c1item_iel_id;
If this is correct, then I don't see the point of using an outer join. Surely if the primary key it_id in table iit does not have a corresponding foreign key in table iip then both iip.iit_change_type and iip.iel_id will be NULL, in which case they will be filtered out by the AND clauses. So why not just use an inner join? Am I missing something? or is the original code nonsense?
回答1:
No, it's not correct -- only those marked with the "(+)" need to be in the LEFT JOIN, the rest are for the WHERE clause:
SELECT `<columns>`
FROM iel_item iit
LEFT JOIN iel_item_property iip ON iip.it_id = iit.it_id
AND iip.iip_change_type = 'I'
AND iip.iel_id = c1item_iel_id
WHERE iit.iit_change_type = 'I'
AND iit.iel_id = c1item_iel_id
Placement matters with OUTER JOINs -- criteria in the ON clause is applied before the JOIN, while criteria in the WHERE is applied after the JOIN. This can greatly affect the result set returned, depends on data and setup. Placement doesn't matter for INNER JOINS - in the WHERE or ON clause, the result set will be the same.
回答2:
No it isn't correct. There were only 3 outer join predicates in the original query, your new one has all 5.
Should be:
cursor c1item (c1item_iel_id number) is
select
`<columns>`
from iel_item iit
left outer join iel_item_property iip
on iip.it_id = iit.it_id
and iip.iip_change_type = 'I'
and iip.iel_id = c1item_iel_id
where and iit.iel_id = c1item_iel_id
and iit.iit_change_type = 'I' ;
回答3:
It can also be rewrited like this:
SELECT columns1
FROM iel_item iit
RIGHT OUTER JOIN iel_item_property iip
ON iip.iip_change_type = 'I'
AND iip.it_id = iit.it_id
AND iip.iel_id = c1item_iel_id
WHERE iit.iit_change_type = 'I'
AND iit.iel_id = c1item_iel_id
Next time, if you need to rewrite Oracle proprietary joins to ANSI SQL compliant joins, here is a tool that can help you do it automatically with less error prone.
来源:https://stackoverflow.com/questions/4796778/conversion-of-legacy-outer-join-to-ansi