views:

228

answers:

4

Sorry , maybe it's trivial but I can't find a way to do this :

table customers

  • customer_id
  • customer_email
  • customer_newsletter (1=yes/0=no)

table orders

  • order_id
  • customer_id
  • order_status (1=ok/0=no_ok)

Each customer can have zero, one or many orders.

I'm trying to make a query to get all the emails of the persons who are :

1/ not yet customers, they have never placed an order but they want to receive my newsletter

or

2/ already customers (one or more orders in the corresponding table). But only if the status of their latest order is OK (I don't want to send the newsletter to problematic customers)

I've tried several things based on subqueries with MAX function but can't find the good formulation

Any advice ? thanks in advance

A: 
SELECT  customer_email
FROM    customers c
WHERE   customer_newsletter
        AND COALESCE(
        (
        SELECT  order_status
        FROM    orders o
        WHERE   o.customer_id = c.customer_id
        ORDER BY
                o.customer_id DESC, o.date_purchased DESC
        LIMIT 1
        ), 1)

Create an index on orders (customer_id, date_purchased) for this to work fast. However, it will work even without the index.

If you want the successful customers receive emails regardless of their newsletter settings, use this:

SELECT  customer_email
FROM    customers c
WHERE   COALESCE(
        (
        SELECT  order_status
        FROM    orders o
        WHERE   o.customer_id = c.customer_id
        ORDER BY
                o.customer_id DESC, o.date_purchased DESC
        LIMIT 1
        ), customer_newsletter)
Quassnoi
In fact, There is also a date_purchased field. I thought it was possible to get the last order with something like SELECT customers_id, orders_id, orders_statusFROM ordersWHERE orders_id IN ( SELECT max(orders_id) FROM orders WHERE orders_status='1' GROUP BY customers_id)I don't have the possibility to define or alter the index on the tables. I can just do Selects
aSa
`@aSa`: updated the answer. It will work even without the index.
Quassnoi
Among customers with OK orders, this only gets those who want the newsletter. That sounds reasonable, but the OP only specified that constraint for customers without orders.
Paul A Jungwirth
A: 

To get customers without orders who want your newsletter you can use a LEFT OUTER JOIN.

Example (untested):

select c.*
from customers c left outer join orders o
on c.customer_id = o.customer_id
where (o.customer_id is null) and customer_newsletter = 1
order by c.customer_id
aiGuru
+1  A: 

1) select * from customers c where customer_newsletter = 1 and not exists ( select * from orders o where c.customer_id = o.customer_id )

2) select * from customers c where 1 = ( select order_status from orders o1 where o1.customer_id = c.customer_id and o1.order_id = ( select max(order_id) from orders o2 where o2.customer_id = c.customer_id) )

Lluis Martinez
+1  A: 

Assuming you can use the greatest order id as the most recent, I think should work:

SELECT c.customer_email
FROM customers c
LEFT OUTER JOIN orders o ON o.customer_id = c.customer_id
WHERE c.customer_newsletter = 1 AND o.customer_id IS NULL
UNION
SELECT c.customer_email
FROM customers c
WHERE customer_id IN 
  (SELECT customer_id FROM orders WHERE order_id IN 
    (SELECT MAX(order_id) FROM orders WHERE order_status = 1 GROUP BY customer_id)
  )
rosscj2533