views:

115

answers:

2

I have the following SQL. Tables defined.

#tbContinent 
--------
ContinentID | ContinentName 

AddressInCountry
--------
AddressID | CountryID

AddressInContinent
--------
AddressID | ContinentID

NameInAddress
--------
AddressID | NameID

I then have the following SQL:

---     Insert into tbName
DECLARE @tbName TABLE 
([ID] int, [AddressID] int, [Name] ntext)

INSERT INTO @tbName 
SELECT 
    [Name].[NameID] AS [ID],
    [Address].[AddressID],
    [Name].[Name]
    FROM NameInAddress INNER JOIN [Name] ON NameInAddress.NameID = Name.NameID
    INNER JOIN [Address] ON NameInAddress.AddressID = Address.AddressID


WHERE [Address].[AddressID] IN
(
    SELECT  AddressInCountry.AddressID
     FROM AddressInCountry 
    UNION ALL
    SELECT  AddressInContinent.AddressID
     FROM #tbContinent AS Continent
     JOIN AddressInContinent ON Continent.ContinentID = AddressInContinent.ContinentID  
)

I've been asked to use joins in place of the nested select. Ive done similar ones using views to create the Union and perform joins on the view, but this one uses a temp table which I can't pass into my view so dont think that I can use the same technique.

I can't use nested selects at all.

Any ideas?

A: 
JOIN 
(
    SELECT  AddressInCountry.AddressID
    FROM AddressInCountry 
    UNION --ALL
    SELECT  AddressInContinent.AddressID
    FROM #tbContinent AS Continent
    JOIN AddressInContinent ON Continent.ContinentID = AddressInContinent.ContinentID        
) AS aic
ON aic.AddressID = [Address].[AddressID]

i'm suggesting UNION over UNION ALL here because you don't want duplicate entries (to match EXISTS functionality).

Rob Farley
...but actually, the Query Optimizer should translate both queries into the same plan.
Rob Farley
Ok, I actualy want to get rid of all nested selects, this would still invole using a nested select. apologies if I wasn't clear
Gribbler
In that case you'd need to duplicate your whole query and change your logic. And I can't see a reason why, other than "no nested queries" standards. Thanks for the -1 though.
Rob Farley
I didn't realise that -1 would affect your rating, if you edit the answer then I can remove it.
Gribbler
Nah, it's fine. I'll let other people judge the value of the post. I was being facetious when I thanked you for it. My own fault, for figuring that you just wanted to remove it from the WHERE clause.
Rob Farley
+1  A: 

Let's take another shot at an answer.

Looking at Set Theory / Relational Algebra, the operation done by a WHERE EXISTS call is known as a LEFT SEMI JOIN (and NOT EXISTS is a LEFT ANTI SEMI JOIN). This means that the join is only used as a filter, it doesn't pull in extra fields, nor does it cause duplicates in the data in the left table.

To implement a semi join without EXISTS, you can do an inner join, making sure there are no duplicates in the right table, as in my other answer.

As you want to extract out the UNION ALL, you would need to put the other join logic in a query with the first part of the union, and then duplicate that logic in the second.

But then the fact that a semi join doesn't duplicate entries on the left means that you need to watch for duplicates, but still somehow include duplicates that could be there in the original version.

Honestly, the correct approach here is to use a subquery, and WHERE EXISTS is the ideal way to implement a Left Semi Join.

Rob Farley