Groups | Blog | Home
all groups > sql server data mining > november 2003 >

sql server data mining : Inner Join experts out there??


news-east.earthlink.net
11/22/2003 12:52:35 AM
The scenario:

two tables

CustomerTable
---------------
CustomerID
OrderID
CustomerName
CustomerEmail
CustomerPhone

OrderTable
---------------
OrderID
ProductID
ProductName
ProductCost

This database was handed to me and I was asked to solve a problem - it looks
like an inner join solution would apply, but I'm not 100% sure.

There are 14 products total (numbers 1 through 14).
I'm looking to get a list of all the customers who have ordered product #1,
UNLESS they've ordered product #14 in which case I don't want to know about
that customer at all.

Any help would be greatly appreciated! I'll watch the newsgroup for the
answer - hopefully your response can help someone else too. However, if you
prefer to email me directly, you can send it to me at bunchah at yahoo dot
com.

Thanks in advance!

(if it'll help, I'll buy the person offering the correct solution a beer -
pending age verification of course) ;)

-Al



Andy Hassall
11/22/2003 1:06:24 AM
On Sat, 22 Nov 2003 00:52:35 GMT, "news-east.earthlink.net"
[quoted text, click to view]

A literal translation could be:

SELECT DISTINCT CustomerID
FROM CustomerTable
WHERE CustomerID IN (SELECT CustomerID
FROM OrderTable
WHERE ProductID = 1)
AND CustomerID NOT IN (SELECT CustomerID
FROM OrderTable
WHERE ProductID = 14)

Or:

SELECT CustomerID
FROM CustomerTable
INNER JOIN OrderTable USING (OrderID)
WHERE ProductID = 1
MINUS
SELECT CustomerID
FROM CustomerTable
INNER JOIN OrderTable USING (OrderID)
WHERE ProductID = 14

--
Andy Hassall (andy@andyh.co.uk) icq(5747695) (http://www.andyh.co.uk)
Dave Hau
11/22/2003 1:17:16 AM
select ct.customerid
from CustomerTable ct
join OrderTable ot
on ct.orderid = ot.orderid
group by ct.customerid
having (count(case ot.productid when 1 then 1 else null end) > 0)
and (count(case ot.productid when 14 then 1 else null end) = 0)
order by ct.customerid


HTH,
Dave



"news-east.earthlink.net" <abunch.goawayspammer@yahoo.nospam.com> wrote in
message news:nryvb.13979$Wy4.3214@newsread2.news.atl.earthlink.net...
[quoted text, click to view]

Dave Hau
11/22/2003 1:31:03 AM
[quoted text, click to view]

Andy, I don't think the second solution will work. First of all, MINUS is
not supported on SQL Server. Second, even if this is run on Oracle, the two
result sets you're performing the minus on are the joined tables, not the
single table CustomerTable. So the two sets are disjoint because ProductID
cannot be 1 and 14 simultaneously. So you'll end up with all the customers
who have ordered product #1, regardless of whether they have ordered product
#14 or not.

Since there's a beer involved here, I have to be a bit particular... ;-)

- Dave


[quoted text, click to view]

Dave Hau
11/22/2003 1:35:10 AM
[quoted text, click to view]

Sorry didn't notice you're selecting only CustomerID instead of *. It does
work.

My bad. You won the beer. :)

- Dave



[quoted text, click to view]

news-east.earthlink.net
11/22/2003 1:50:17 AM
SELECT DISTINCT cart_id
FROM OrderTable
WHERE cart_id
IN (
SELECT cart_id
FROM CartTable
WHERE product_index =1 ) AND cart_id NOT
IN (
SELECT cart_id
FROM CartTable
WHERE product_index =14 )

After I switched the fields and table names out to match the real table
names ( they were confusing the issue a bit) I tried the quer(y/ies) and I
get errors on both.

Maybe I should clarify - this is running in a MySQL database server - though
with straight SQL I would think this wouldn't matter much, no?

I moved the structure of the actual tables to a database on my home server
and punched a hole in my firewall to allow you to look at this first hand -
mind you, there are only a few records and they're made up, but they should
be sufficient enough to let you tinker...

surf to http://maple.homelinux.com/phpmyadmin/index.php
account : aaron
pass: pass123

I'll leave it up and running this evening - the account has limited rights
(to that database only)...

take a gander?

BTW - for the speedy response, I'll buy both of you guys a beer...name your
poison!
[quoted text, click to view]

Andy Hassall
11/22/2003 2:06:15 AM
On Sat, 22 Nov 2003 01:50:17 GMT, "news-east.earthlink.net"
[quoted text, click to view]

What errors?

[quoted text, click to view]

It makes a big difference - MySQL has large gaps in its SQL syntax - in
particular, no subqueries or set operations (i.e. MINUS).

(Subqueries are going into the alpha 4.1 version, I think UNION went into 4.0
at some point, don't know about MINUS).

[quoted text, click to view]

404 Object not found.

A variation on Dave's query to account for MySQL's limitations and quirks
(identifiers case-sensitive, cannot reference aggregates in HAVING clauses only
their aliases, JOIN must be INNER JOIN) comes up with:

select ct.CustomerID,
count(case ot.ProductID when 1 then 1 else null end) num_1,
count(case ot.ProductID when 14 then 1 else null end) num_14
from CustomerTable ct
inner join OrderTable ot
on (ct.OrderID = ot.OrderID)
group by ct.CustomerID
having num_1 > 0
and num_14 = 0
order by ct.CustomerID

This works against MySQL 3.x, 'cos I just ran it.

--
Andy Hassall (andy@andyh.co.uk) icq(5747695) (http://www.andyh.co.uk)
Dave Hau
11/22/2003 2:23:14 AM
[quoted text, click to view]

IMHO, no need for the DISTINCT. The "group by ct.CustomerID" will always
give you distinct values of CustomerID.

- Dave


[quoted text, click to view]

Andy Hassall
11/22/2003 2:23:33 AM
[quoted text, click to view]

OK, that's wrong, looks like I was thinking of something else. So going closer
back to Dave's query:

select DISTINCT ct.CustomerID
from CustomerTable ct
inner join OrderTable ot
on (ct.OrderID = ot.OrderID)
group by ct.CustomerID
having count(case ot.ProductID when 1 then 1 else null end) > 0
and count(case ot.ProductID when 14 then 1 else null end) = 0
order by ct.CustomerID;

--
Andy Hassall (andy@andyh.co.uk) icq(5747695) (http://www.andyh.co.uk)
Andy Hassall
11/22/2003 2:40:22 AM
On Sat, 22 Nov 2003 02:23:14 GMT, "Dave Hau"
[quoted text, click to view]
[snip]

[quoted text, click to view]

Ah, yes - that's true.

--
Andy Hassall (andy@andyh.co.uk) icq(5747695) (http://www.andyh.co.uk)
news-east.earthlink.net
11/22/2003 2:50:25 AM
select DISTINCT ct.cart_id
from OrderTable ct
inner join CartTable ot
on (ct.cart_id = ot.cart_id)
group by ct.cart_id
having count(case ot.product_index when 1 then 1 else null end) > 0
and count(case ot.product_index when 14 then 1 else null end) = 0
order by ct.cart_id;

Thanks Andy, that worked PERFECTLY!
Ok, now what kind of beer do you drink? (or wine?)

Dave - thanks to you too - it's nice to know I'm not the only one working on
a Friday night. :)

-Al

[quoted text, click to view]

Christian Boult
11/23/2003 5:40:44 PM
Off the top of my head how about something like this.

select
a.[CustomerID],
max( b.[ProductID] ) as [MaxProductID],
min( b.[ProductID] ) as [MinProductID]
from
CustomerTable a
inner join OrderTable b on
a.[OrderID] = b.[OrderID]
group by a.[CustomerID]
having min( b.[ProductID] ) = 1 and max( b.[ProductID] ) < 14

Chris.


"news-east.earthlink.net" <abunch.goawayspammer@yahoo.nospam.com> wrote in
message news:nryvb.13979$Wy4.3214@newsread2.news.atl.earthlink.net...
[quoted text, click to view]

raghuraman_ace NO[at]SPAM rediffmail.com
11/24/2003 5:26:32 AM
[quoted text, click to view]

Hi ,
Here is my reply

select customertable.* c1 from customertable inner join ordertable o1
on c1.orderid = o1.orderid where c1.orderid = 1 and o1.orderid <> 14

With Thanks
AddThis Social Bookmark Button