views:

75

answers:

3

I have been tasked with returning a negative selection from our sql database. I'll define the criteria as best i can. Thus far I haven't crafted a query that has worked.

Business Table

[Bus Name] [Bus ID]

Activity Table

[Activity ID] [Bus ID]

Activity Extension Table

[Ext ID] [Activity ID] [Bus ID]

I need the Business names for all businesses that do not have a record with that businesses id # in the associated tables. Simply put, all businesses without activities. The Business ID can be present in one or both of the associated tables.

This has caused me trouble for a few hours while trying to craft queries with joins and not exists or not in statements. No success.

Any ideas?

Thanks D

+3  A: 

SELECT * FROM businesses WHERE business.id NOT IN (SELECT DISTINCT business_id FROM activities)

Jamie Wong
+1 but DISTINCT in the subquery is superfluous.
Bill Karwin
@Bill I was wondering if there might be some performance gain from doing that. Come to think of it, it might be a performance loss.. Hmm..
Jamie Wong
YMMV. In many databases, the DISTINCT query modifier does its work by sorting the result of the query, which can be costly. I'd trust more that MS SQL Server knows how to optimize the NOT IN query. Or else turn it into a NOT EXISTS query.
Bill Karwin
+1  A: 

I would use a combination of a left join and a union, something like:

select * from Business b left join (select id, bid from Activity union select id, bid from ActivityExtension) a on b.id=a.bid where a.bid=null 
shipmaster
+1 Alternatively, you could left join to both tables, and where both are null, there is no match.
Bill Karwin
+2  A: 

Using NOT IN


SELECT b.*
  FROM BUSINESS b
 WHERE b.business_id NOT IN (SELECT a.business_id
                               FROM ACTIVITY a)
   AND b.business_id NOT IN (SELECT ae.business_id
                               FROM ACTIVITY_EXTENSION ae)

Using NOT EXISTS


SELECT b.*
  FROM BUSINESS b
 WHERE NOT EXISTS (SELECT NULL 
                     FROM ACTIVITY a
                    WHERE a.business_id = b.business_id)
   AND NOT EXISTS (SELECT NULL 
                     FROM ACTIVITY_EXTENSION ae
                    WHERE ae.business_id = b.business_id)

Using LEFT JOIN/IS NULL


   SELECT b.*
     FROM BUSINESS b
LEFT JOIN ACTIVITY a ON a.business_id = b.business_id
LEFT JOIN ACTIVITY_EXTENSION ae ON ae.business_id = b.business_id
    WHERE a.business_id IS NULL
      AND ae.business_id IS NULL

Conclusion


Because the relationship is a foreign key (business_id), it's safe to assume none of them to be null. In which case, NOT IN and NOT EXISTS are the best means of looking for missing values in SQL Server. LEFT JOIN/IS NULL is less efficient - you can read more about it in this article.

OMG Ponies
Thanks for the replies. I ended up figuring out the left join method on my own but I am baffled as to why the other two methods aren't working. Below is the query I crafted after looking through your response and I keep getting 0 lines returned.select T1.namefrom dbo.AccountBase T1where T1.accountid not in (select T2.partyidfrom dbo.ActivityPartyBase T2)and T1.deletionstatecode = 0T1.accountid is equivalent to T2.partyid when an activity exists for a business. Thanks
Donovan