WHERE value IS NOT IN (subquery)

懵懂的女人 提交于 2020-01-02 02:04:26

问题


I've been struggling with this query. I have two tables. One with coupons and Invoicenumbers. One with Invoicenumbers and customer names.

I need to get the customers who have not used a given coupon.

Here are the tables:

Promotion table:

Promotions
Invoice | Coupon
----------------
1       | couponA
2       | couponB
3       | couponB

Orders Table:

Orders
Invoice | Customer
------------------
1       | Jack
2       | Jack
3       | Jill

So Jack has used coupons A and B. And Jill has only used coupon B.

If my query were select customers who have not used coupon A, I should get Jill.

This works, but it seems clumsy and slow. Is there a better way?

SELECT Customer 
FROM Promotions INNER JOIN Orders
ON Promotions.Invoice = Orders.Invoice
WHERE Customer NOT IN(
    SELECT Customer 
    FROM Promotions INNER JOIN Orders
    ON Promotions.Invoice = Orders.Invoice
    WHERE Coupon = couponA)
GROUP BY Customer

Thanks for looking!

edit: Here's an SQLFiddle schema http://sqlfiddle.com/#!2/21d31/6


回答1:


 SELECT DISTINCT o2.customer FROM ORDER o2 
LEFT JOIN (promotions p1 
    JOIN Orders o1 ON p1.cuopon = 'CuoponA' AND p1.invoice = o1.invoice ) p3 
    ON o2.customer = p3.customer 
WHERE p3.customer IS NULL



回答2:


Updated: We should use prefer to use joins for better performance when its easy to do for us. Join vs. sub-query

Sql Fiddle

Select distinct Customer from orders o
join 
(
  SELECT distinct Customer as changedname FROM Orders o2 
  join
  (
     Select distinct invoice from Promotions where Coupon='couponA'
  ) t3
  on o2.invoice = t3.invoice      
) t2
on o.customer != t2.changedname;

Note: I changed column name customer for t3 because two joined tables must have different column names

Explanation:

Using inner or sub query is expensive when you have big data. use joins instead, lets learn converting subquery to join

With Subquery We had:

Select distinct Customer from orders where customer not in 
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));

First step:

Select distinct Customer from orders o
join 
(
  SELECT distinct Customer as changedname FROM Orders where invoice in
  (Select distinct invoice from Promotions where Coupon='couponA')
) t2
on o.customer != t2.changedname;

2nd step:

Select distinct Customer from orders o
join 
(
  SELECT distinct Customer as changedname FROM Orders o2 where invoice 
  join
  (
     Select distinct invoice from Promotions where Coupon='couponA'
  ) t3
  on o2.invoice = t3.invoice      
) t2
on o.customer != t2.changedname;

And that's it, much faster for tables having numerous rows

Original answer:

Use not in. Have a look.

Select distinct Customer from orders where customer not in 
(SELECT distinct Customer FROM Orders where invoice in
(Select distinct invoice from Promotions where Coupon='couponA'));

Edit I have added distinct to make query faster

SQL Fiddle




回答3:


Try this with a right join

SELECT Customer, Coupon
FROM Promotions 
RIGHT JOIN Orders ON Promotions.Invoice = Orders.Invoice
    AND Coupon = 'couponA'
GROUP BY Customer
HAVING Coupon IS NULL



回答4:


Try this query instead:

SELECT DISTINCT Customer
FROM Orders o1
WHERE NOT EXISTS (
    SELECT 1 
    FROM Orders o2
    INNER JOIN Promotions ON Promotions.Invoice = o2.Invoice
    WHERE o1.Customer = o2.Customer AND Coupon = 'couponB')

The idea is to get rid of the GROUP BY by removing a join in the top part of the query, and also eliminate the NOT IN by making a coordinated subquery.

Here is a link to sqlfiddle.



来源:https://stackoverflow.com/questions/14017369/where-value-is-not-in-subquery

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!