Inactive customers mysql query optimization - mysql

I have a customer table with million of records.
Customer
id | name | .....
I also have an orders table with
id | custID | orderDate | ....
I need to find all the people who have not placed an order for more than 30 days.It should also include people who have never placed the order
select name,customer.id from customer where id in
(select custID from orders where datediff(curdate(),orders.orderDate) > 30 )
union
select name,customer.id from customer left join orders on customer.id = orders.custID where orders.id is null
How can i optimize the query ?

Try
select name,t.id
from customer t where
not exists (
select 1
from orders where
custID=t.id
and
datediff(curdate(),orders.orderDate) <= 30 )

Try this one
Select Customer.Custid,
Customer.name
from Customer
left join orders on
customer.custid = orders.custid and
datediff(getdate(),orders.orderdate)>30)
where
orders.id is null

Related

Sql Query Difficult with sum

I have a table Customers ( id | name ), with id and name of fornitori,
and another table Money (id | idcustomers | give | have ).
Give and have are int field, with the money that the customer gave and the sum create the balance.
I would like to create a query that shows for each customer the name and the different
of SUM(GIVE) - SUM(HAVE) where money.idcustomers = customers.id
Just grouping by customer id should do the trick:
SELECT Customers.name, SUM(GIVE) - SUM(HAVE) total
FROM Customers
JOIN Money ON Money.idcustomers = Customers.id
GROUP BY Customers.id
SQL Fiddle demo; http://sqlfiddle.com/#!2/339032/2
SELECT C.name, (SUM(M.give)-SUM(M.Have)) AS total
FROM Customors C, Money M
WHERE C.id = M.idcustomers
ORDER BY C.name
GROUP BY C.name

Select max value from different tables in mysql

I want to select the most expensive product each customer bought, but I have the information in 3 tables: Customers, Purchases, ProductsPrices.
Tables look like:
Customers:
Customer_ID | Customer_Name
Purchases:
Customer_ID | Product_ID
ProductPrices:
Product_ID | Price
What i'm running is:
SELECT
Customer_Name, max(Price), Purchases.Product_ID
FROM Customers
LEFT JOIN Purchases
ON Customers.Customer_ID=Purchases.Customer_ID
LEFT JOIN ProductPrices
ON Purchases.Product_ID=ProductPrices.Product_ID
GROUP BY Customer_Name
ORDER BY ABS(Price) DESC
;
And the output i'm getting is the names and the highest purchase correct, but the product_id is the first, and not associated with the highest price.
Can you help me to spot what am I doing wrong?
EDIT:
To make it easier for you, I created this:
http://sqlfiddle.com/#!2/db7f9/1
Try this:
select distinct c.Customer_Name,pp.Product_Id,m.Price
from
(select Customer_ID,max(Price) as Price
from Purchases p join ProductPrices pp on (p.Product_ID=pp.Product_ID)
group by Customer_ID) m
join Customers c on (m.Customer_ID=c.Customer_ID)
join ProductPrices pp on (pp.Price=m.Price)
join Purchases p on (m.Customer_ID=p.Customer_ID and p.Product_ID=pp.Product_ID)
Note: If a customer purchased multiple products with the same price, this will give you muliple rows per Customer.
try this
SELECT Customer_Name, max(Price) price , Product_ID FROM (
SELECT
Customer_Name, Price, Purchases.Product_ID
FROM Customers
INNER JOIN Purchases
ON Customers.Customer_ID=Purchases.Customer_ID
INNER JOIN ProductPrices
ON Purchases.Product_ID=ProductPrices.Product_ID
ORDER BY ABS(Price) DESC
)t
GROUP BY Customer_Name
DEMO HERE
OUTPUT:
CUSTOMER_NAME PRICE PRODUCT_ID
John 30000 3
Kate 30000 3
Peter 20000 2

Combine database tables and to form into one table

I have two tables, one is Customer Detail and the other is Order Detail. Each time the Customer will order something it will store it in database. How can I find which customer orders and how many times they order and combine the customer name and orders?
CUSTOMER DETAIL:
ID NAME AGE COUNTRY
1 AAA 22 US
2 BBB 26 UK
3 CCC 25 TN
ORDER DETAIL:
ID ITEMS PRICE QUANTITY
1 APPLE 5
1 ORANGE 6
1 MANGO 4
Customer AAA has many orders.
EXPECTED RESULT:
CUSTOMERDETAIL ORDERDETAIL
AAA (HOW MANY TIMES HE ORDER AND ORDER DETAILS)
Create Table Customer (CustomerId int identity(1,1),Name varchar(20))
Create Table OrderDetail(OrderDetailId int identity(1,1), CustomerId int, Item varchar(20), Quantity int)
Insert into Customer values('AAA')
Insert into Customer values('BBB')
Insert into Customer values('CCC')
Insert into OrderDetail values(1,'Apple',10)
Insert into OrderDetail values(1,'Banana',10)
Insert into OrderDetail values(1,'Mango',10)
select y.total, x.Item,x.quantity from
(
select c.customerId as customerId, d.Item, d.quantity from customer c inner join orderdetail d
on c.customerId = d.customerId
)x
inner join
(
select customerid, COUNT(customerId)as total from orderdetail group by customerId
)y
on x.customerId = y.customerId
Suppose you have the schema like this:
Customer table (customer)
ID (Customer Id) int primary key
Name varchar(100)
Order Table (orders)
ID (Order ID) int
cusotmer_id (reference id of customer table primary key-ID) int
quality int
price float
First Count of Order against eash customer:
select count(o.customer_id) as total_order, c.* from customer c left join orders o on c.ID = o.customer_id
Orders listing against a single customer:
select c.*, o.* from customer c inner join orders o on c.ID = o.customer_id where c.ID = 1
I hope this will help you.
The following query gives what i expect.
SELECT name,items,price FROM customerdetail INNER JOIN orderdetail ON customerdetail .sno=orderdetail .id WHERE id=1 ;

WHERE value IS NOT IN (subquery)

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
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'));
Converting sub-query to join
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
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
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.
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

Complex query with many joins

I am trying to make one query, to get some statistic data from database.
My tables structure described here:
PRODUCTS
id | price | buy_price | vendor_code | ...
ORDERS
id | shipping_method_id | ...
ORDER_ITEMS
id | order_id | product_id | quantity | ...
SHIPPING_METHODS
id | cost | ...
SUPPLIERS
id | code | ...
I want to get data like this. In words, I am making reports on Product total income, expenses and quantity of buys in my ecommerce, and want them to group by supplier. I wrote this sql:
SELECT orders.id,
suppliers.code,
COUNT(products.id)*items.quantity buys,
SUM(products.price*items.quantity + shipping_methods.cost) sales,
SUM(products.buy_price*items.quantity) expenses
FROM `orders` orders
INNER JOIN `order_items` items ON items.order_id = orders.id
INNER JOIN `products` products ON items.product_id = products.id
INNER JOIN (SELECT DISTINCT suppliers.code FROM `suppliers`) suppliers
ON products.vendor_code LIKE CONCAT(suppliers.code, '%%')
INNER JOIN `shipping_methods` shipping_methods ON orders.shipping_method_id = shipping_methods.id
WHERE (
orders.delivery_date_to BETWEEN '2011-11-18' AND '2011-11-19'
)
GROUP BY suppliers.code, orders.id
ORDER BY buys DESC
this returns to me this data:
order_id code buys sales expenses
85 SB 4 1504 1111.32
84 VD 2 496 350.82
60 lg 2 1418 1052.31
88 SB 1 376 277.83
When I change GROUP BY suppliers.code, orders.id to GROUP BY suppliers.code, it returns almost correct data, I mean data is grouped by code, but counting is wrong. Admit that sales and expenses are correct
order_id code buys sales expenses
85 SB 8 1880 1389.15
60 lg 2 1418 1052.31
84 VD 2 496 350.82
If u see SB counted total 8 sales, but really there are only 5, as u can see in previous table. I'm sure I missed something in my query, but cant understand how to correct this.
PS field order_id are unused in my further scripts, I use it because django's Model.objects.raw() query does need to have primary key in result, don't really understand why
try this query.
SELECT t1.code, SUM(t1.buys), SUM(t1.sales) FROM (
SELECT orders.id,
suppliers.code,
COUNT(products.id)*items.quantity buys,
SUM(products.price*items.quantity + shipping_methods.cost) sales,
SUM(products.buy_price*items.quantity) expenses
FROM `orders` orders
INNER JOIN `order_items` items ON items.order_id = orders.id
INNER JOIN `products` products ON items.product_id = products.id
INNER JOIN (SELECT DISTINCT suppliers.code FROM `suppliers`) suppliers
ON products.vendor_code LIKE CONCAT(suppliers.code, '%%')
INNER JOIN `shipping_methods` shipping_methods ON orders.shipping_method_id = shipping_methods.id
WHERE (
orders.delivery_date_to BETWEEN '2011-11-18' AND '2011-11-19'
)
GROUP BY suppliers.code, orders.id
ORDER BY buys DESC
) AS t1
GROUP BY t1.code
Edit: I've forgotten SUM() parts. Just added, please retry if you've already tried.