Search code examples
sqlt-sqlsql-server-2008-r2reportingcross-join

Unsold product query without a cross join?


I'm working on a stored procedure for "unsold products".

Here's a summary of the approach I've taken so far.

Note: in production there will be a max 7 products and the sales table is has approximately 18,000 growing slowly relative to current magnitude.

My question is: is there another approach I might consider to avoid the potential pit fall of an exploding cross join?

declare @products table (
    productName varchar(50)
)

declare @customers table (
    customerName varchar(50)
)

declare @sales table (
    customerName varchar(50),
    productName varchar(50)

)

insert into @products values ('Product1'), ('Product2')

insert into @customers values ('Customer1'), ('Customer2')

insert into @sales values
     ('Customer1', 'Product1')
    ,('Customer1', 'Product2')
    ,('Customer2', 'Product1')

-- want a row for each customer and each product they
-- have not been sold 
select *
from @customers C
cross join @products P
where not exists(select productName 
                 from @sales S
                 where S.customerName = C.customerName and
                       S.productName = P.productName)

Solution

  • I think you're doing it right, but you might check if EXCEPT gives you better performance:

    select C.CustID, P.ProdID
    from @customers C
    cross join @products P
    EXCEPT
    SELECT CustID, ProdID
    from @sales S
    group by CustID, ProdID
    

    And obviously if you can pare down the client list, it would help, like eliminating anyone who hasn't purchased anything in the last year.