January 29, 2010 at 7:19 am
I have two main tables and a connecting table that I want to join together.
The first table is Customers:
CustomerID, CustomerName
The second table is Product Types
ProductID, ProductName
And the connecting table holds the info to join them together:
CatID, CustomerID, ProductID
It's pretty simple to join them together and see what customers have received which products, but They want to see what products a customer hasn't received.
I know I can do it in the programming code (for each Customer{ for each product{ not exists in table(customerid and productid)}}) but it would be nice to know how to do this in SQL.
does anyone have any ideas?
January 29, 2010 at 7:33 am
Without table defs (CREATE TABLE statements), sample data (as a series of INSERT INTO statements), all I could come up with is this:
select
c.CustomerID,
c.CustomerName,
p.ProductID,
p.ProductName
from
dbo.Customer c
cross join dbo.Product p
where
not exists(select 1 from dbo.CustomerProduct cp where cp.CustomerID = c.CustomerID and cp.ProductID = p.ProductID);
January 29, 2010 at 7:33 am
there's two concepts you'll want to use here to get the desired results:
using a CROSS JOIN can give you every possible combination.
using a LEFT OUTER JOIN can show you results that do not exist in your connecting table.
--all possible combinations
SELECT * FROM
(
SELECT
Customers.CustomerID,
Customers.CustomerName,
[Product Types].ProductID
[Product Types].ProductName
FROM Customers
CROSS JOIN [Product Types] --cross join gets every possible value
) MyCombinedAlias
LEFT OUTER JOIN [connecting table]
ON MyCombinedAlias.CustomerID = [connecting table].CustomerID
AND MyCombinedAlias.ProductID = [connecting table].ProductID
WHERE [connecting table].CatID IS NULL --if it doesn't exist in the connecting table so far
Lowell
January 29, 2010 at 8:28 am
Thats awesome. Somehow I had forgotten about cross joins. If you don't use it you lose it I guess.
So yeah, that'll work perfectly. Thanks a ton
February 1, 2010 at 10:04 am
Hi Lynn,
not exists(select 1 from dbo.CustomerProduct cp where cp.CustomerID = c.CustomerID and cp.ProductID = p.ProductID);
can you explain, why you use "1" in the exists-statement instead of "*"?
I also know some code examples with: "count(1)", but never understood, if this led to any performance enhancement in the old days
or still does, or if there is another reason...
Thanks in advance!
Arthur
February 1, 2010 at 10:16 am
In this case (and correct me if I'm wrong), because you are checking if something doesn't exists, 1 is like true. You don't need to return *, you just want to know if something is present at all, and do something if it isn't.
NOT EXISTS works the opposite as EXISTS. The WHERE clause in NOT EXISTS is satisfied if no rows are returned by the subquery.
So you don't have to have it return a bunch of stuff. a canned 1 will work just fine, because it will only show up if something is going to be returned.
February 1, 2010 at 2:07 pm
Thank you for your fast reply!
So you don't have to have it return a bunch of stuff. a canned 1 will work just fine, because it will only show up if something is going to be returned.
NOT EXISTS Returns TRUE if a subquery contains 0 rows. So using '1' is more a matter of style?
So I could use
select * from table1.column1 t1 where exists (select 'Yay!' from table2 where column2=t1.column1)
to have a little laugh while I'm scripting?
February 1, 2010 at 2:18 pm
Tested 'Yay!' with not exists and it works just as good as 1.
I'll be the first to admit that I'm not a SQL master, so I don't know if there is any kind of performance gains to one versus the other, but yes, it does work.
February 1, 2010 at 2:18 pm
To make things a little clearer, I hope, the following are equivalent:
select * from dbo.Customer cus where exists(select * from dbo.Order ord where ord.CustomerID = cus.CustomerID);
select * from dbo.Customer cus where exists(select 1 from dbo.Order ord where ord.CustomerID = cus.CustomerID);
In the first, SQL Server determines that it really doesn't need to return any data from the table, so it will generate a plan like the one the second will; or so I have been told.
Viewing 9 posts - 1 through 8 (of 8 total)
You must be logged in to reply to this topic. Login to reply