1

I've got 2 tables.

'Order details'
OrderID | Quantity | UnitPrice | ProductID
  1002  |    19    |    17     |    824
  1002  |    5     |    15     |    285
  1003  |    7     |    17     |    824
  1003  |    7     |    15     |    285
  1003  |    7     |    11     |    205
  1004  |    12    |    11     |    205


'Orders'
OrderID | CustomerID
  1002  |   224
  1003  |   348
  1004  |   224

I need to find CustomerIDs that have the same orders (ProductID) as another CustomerID, for instance ID number 224. All the orders must be taken, I mean all its OrderIDs. So the output would be 348, as this id has absolutely the same productids in his orders.

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
Oleksii Kryzh
  • 231
  • 1
  • 2
  • 11

3 Answers3

1

If you want customers with the same products:

with od1 as (
      select distinct o.customerid, od.productid
      from orderdetails od join
           orders o
           on o.orderid = od.orderid
     ),
     od as (
      select od1.*,
             (select count(*) from od1 od2 where od2.customerid = od1.customerid) as numproducts
      from od1
     )
select od.customerid
from od od join
     od od2
     on od.productid = od2.productid and od.numproducts = od2.numproducts and
        od.customerid = 224
group by od.customerid
having count(*) = od.numproducts;

The purpose of the CTE is simply to get one row per customer, product, and the count of products. The outer query counts the number of matches between two customers. The number of matches needs to match the number of products.

This returns exact matches. The second customer has to have exactly the same products, no more, no less.

Note: This returns the original customer (easily filtered out with a where clause).

Gordon Linoff
  • 1,242,037
  • 58
  • 646
  • 786
0

In the following sketch I list all the orders that has exactly the same products of some order made by the Customer Id 224

select distinct o2.OrderId
from    
    Orders o1, Orders o2
where 
    o1.CustomerId = 224
    and o1.OrderId <> o2.OrderId
    and not exists (
        select 1 
        from 
            "Orders details" od1 
            full outer join "Order details" od2 on 
                od1.OrderId = o1.OrderId 
                and od2.OrderId = o2.OrderId 
                and od1.ProductId = od2.ProductId
        where
            od1.OrderId is null or od2.OrderId is null
    )

the rest should be easy.

If your DBMS does not support full outer join, you can split it into two left join like this:

select distinct o2.OrderId
from    
    Orders o1, Orders o2
where 
    o1.CustomerId = 224
    and o1.OrderId <> o2.OrderId
    and not exists (
        select 1 
        from 
            "Orders details" od1 
            left join "Order details" od2 on 
                od1.OrderId = o1.OrderId 
                and od2.OrderId = o2.OrderId 
                and od1.ProductId = od2.ProductId
        where
            od2.OrderId is null
    )
    and not exists (
        select 1 
        from 
            "Orders details" od1 
            left join "Order details" od2 on 
                od1.OrderId = o2.OrderId 
                and od2.OrderId = o1.OrderId 
                and od1.ProductId = od2.ProductId
        where
            od2.OrderId is null
    )
0
with cte1 as 
(  select CustomerID, ProductID 
     from order 
     join detail
       on order.OrderID  = detail.OrderID )
, cte2 as 
(  select CustomerID, count(*) as cnt 
   from cte1 
   group by CustomerID
)
select cte2a.CustomerID, cte2b.CustomerID
  from cte2 as cte2a
  join cte2 as cte2b
    on cte2a.CustomerID < cte2a.CustomerID
   and cte2a.cnt< cte2a.cnt
  join cte1 as cte1a
    on cte1a.CustomerID = cte2a.CustomerID
  join cte1 as cte1b
    on cte1b.CustomerID = cte2b.CustomerID
   and cte1a.ProductID  = cte1b.ProductID 
 group by cte2a.CustomerID, cte2b.CustomerID, cte2a.cnt
 having count(*) = cte2a.cnt
paparazzo
  • 44,497
  • 23
  • 105
  • 176