Select max value from different tables in mysql - 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

Related

Find top 3 most ordered product per supplier in mysql 8.x

I'd like to find the top 3 most ordered products per supplier in mySql. Here's my simplified model and its tables (primary keys are in italics):
Product :
product_id,
name,
supplier_id
Supplier :
supplier_id, name
Order_item :
order_item_id, product_id
So 1 supplier can have N products, 1 order_item has 1 product.
So far this is what i was able to get :
SELECT count(*), p.name, s.name FROM order_item oi
JOIN product p on oi.product_id = p.product_id
JOIN supplier s on p.supplier_id = s.id
GROUP BY p.product_id, s.id
ORDER BY COUNT(*) DESC
LIMIT 3;
But this gives me the 3 most ordered products among every supplier, not per supplier. In the exemple below, my sql request would give me this :
Count
Product.name
Supplier.name
1450
Strawberry
Good ol'farm
1200
Salmon
Fishing
1150
Shrimp
Fishing
But I would like a result similar to this (N groups of top 3's):
Count
Product.name
Supplier.name
1450
Strawberry
Good ol'farm
1000
Orange
Good ol'farm
350
Lemon
Good ol'farm
1200
Salmon
Fishing
950
Carp
Fishing
1150
Shrimp
Fishing
Thank you.
In MySQL 8 you should be able to:
WITH prodSupCounts AS (
SELECT ROW_NUMBER() OVER(partition by s.name ORDER BY count(*) DESC) rn, p.name, s.name, count(*) as ct
FROM
order_item oi
JOIN product p on oi.product_id = p.product_id
JOIN supplier s on p.supplier_id = s.id
GROUP BY p.product_id, s.id
)
SELECT * FROM prodSupCounts WHERE rn <= 3
This should provide a column rn that is an incrementing counter from 1, in order of descending sale count, and the counter starts from 1 per supplier, so saying rn<=3 gives 3 rows per supplier

Select from multiple tables even if one doesn't have any corresponding record

I have three tables: product, sale and purchase.
I need to get the sum of sales and the sum of purchases of the products.
Even if no sales were made, I need it to show the purchases and vice-versa.
Something like:
Product | Sum of sales | Sum of purchases |
____________________________________________
product 1 | 10000 | 45000 |
product 2 | 20000 | 0 (or null) |
product 3 | 0(or null) | 20000 |
I've tried this, but it'll only return products that have both sales and purchases simultaneously:
select prod.name, sum(s.total), sum(p.total)
from product prod
inner join sale s on s.prod_id = prod.id
inner join purchase p on p.prod_id = prod.id
group by 1;
Thanks in advance.
Your query has a couple of issues. Firstly, because of the INNER JOIN it will (as you found) only return values for products which have both sales and purchases. This can be resolved by using LEFT JOIN (with an optional COALESCE to convert null values into 0). The second problem is that you will get duplicate rows from your JOIN where there is more than one sale or purchase of a product. To work around that, you need to perform the aggregation in derived tables for sales and purchases:
SELECT pr.name,
s.total AS sales, -- will show null if no sales
COALESCE(p.total, 0) AS purchases -- will show 0 if no purchases
FROM product pr
LEFT JOIN (SELECT prod_id, SUM(total) AS total
FROM sale
GROUP BY prod_id) s ON s.prod_id = pr.id
LEFT JOIN (SELECT prod_id, SUM(total) AS total
FROM purchase
GROUP BY prod_id) p ON p.prod_id = pr.id

Pulling last 10 orders from mysql table

I'm new to mysql and I'm trying to figure out if there is a way that you can pull information from the the last 5 most recent orders.
I'm trying to pull orderNumber, productName, and firstname for last 5 most recent orders.
I created 2 dummy tables that I'm working with:
Table:
orders
Fields:
orderNumber
customerOid
orderInformationOid
purchaseDateTime
Table:
customerData
Fields:
customerOid
firstName
middleInitial
lastName
Table:
products
Fields:
productOid
productName
companyOid
I was thinking an INNER JOIN but how to determine the most recent orders?
I suppose there's a productOid column in your orders table, then you can use this query:
SELECT o.orderNumber, p.productName, c.firstname
FROM
(SELECT orderNumber, customerOid, productOid
FROM orders
ORDER BY purchaseDateTime DESC
LIMIT 5) o
INNER JOIN customers c ON o.customerOid = c.customerOid
INNER JOIN products p ON o.productOid = p.productOid

Inactive customers mysql query optimization

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

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.