MySQL Retrieve Lowest Value in Multi-table Query - mysql

My goal is to retrieve the recorded purchase price for an item on an accepted purchase order.
Purchase_Orders table contains metadata for the order, such as the order number and its status (e.g., 1 for accepted, 0 for declined).
Purchase_Ord_Contents table contains contents records, which are linked via foreign key to the parent purchase order on a shared index order_number)
For example: I have two orders in my database, one has been accepted and the other has been declined. The data is represented as follows:
=========================================
PURCHASE_ORDERS TABLE
=========================================
id | order_number | order_status
-----------------------------------------
1 PO_100 0
2 PO_101 1
3 PO_102 1
===================================================
PURCHASE_ORD_CONTENTS TABLE
===================================================
id | order_number | purchase_price | sku
---------------------------------------------------
1 PO_100 1.50 APPLE
2 PO_100 1.50 ORANGE
3 PO_101 2.00 APPLE
4 PO_101 2.00 ORANGE
5 PO_102 1.75 BANANA
The query should return rows 3, 4 and 5, since PO_101 was accepted, whereas PO_100 was declined and row 5 is not only the only record for the given SKU, it was also on an accepted order. I've tried a few different approaches, but I always seem to end up either leaving out parts that were on an unaccepted Purchase Order, or retrieving the wrong order_number for the lowest purchase_price.
Here is what I have thus far (not working properly)
SELECT a.*
FROM purchase_ord_contents AS a
JOIN (SELECT sku,
MIN(purchase_price) AS min_price
FROM purchase_ord_contents
GROUP BY sku) AS b
ON ( a.sku = b.sku
AND a.purchase_price = b.min_price )
WHERE a.order_number
IN (
SELECT order_number
FROM purchase_orders
WHERE order_status != 0
)
This query successfully returns the records from the purchase_ord_contents table, however it omits records of the lowest purchase_price that were on a Purchase Order with an order_status of 0.
Any guidance would be greatly appreciated, I am not very well versed in "advanced" SQL queries as you have probably determined by now. Thank you for your time and please do not hesitate to ask if I should provide any further information.

This could be what you are looking for:
SELECT sku, purchase_price, order_number
FROM (
SELECT MIN(purchase_price) AS purchase_price, sku
FROM purchase_ord_contents
JOIN purchase_orders USING (order_number)
WHERE purchase_orders.order_status = 1
GROUP BY sku
) AS min_sku_price -- this is the lowest sale price for each SKU
JOIN purchase_ord_contents USING (sku, purchase_price) -- gets all orders having sold a SKU at its lowest price
JOIN purchase_orders USING (order_number)
WHERE purchase_orders.order_status = 1
Notice this will return several rows for one given SKU if the lowest price for this SKU was offered in several orders.

If I understand correctly I think you want this:
SELECT po.order_number, poc.sku, min(poc.purchase_price)
FROM purchase_orders AS po
JOIN purchase_ord_contents AS poc ON poc.order_number = po.order_number
WHERE po.order_status != 0
GROUP by po.order_number, poc.sku
order by po.order_number, poc.sku

Related

Joining multiple columns into one with union, exclude results with same id

I want to join columns from multiple tables to one column, in my case column 'battery_value' and 'technical_value' into column 'value'. I want to fetch data for only given category_ids, but because of UNION, I get data from other tables as well.
I have 4 tables:
Table: car
car_id model_name
1 e6
Table: battery
battery_category_id car_id battery_value
1 1 125 kW
Table: technical_data
technical_category_id car_id technical_value
1 1 5
3 1 2008
Table: categories
category_id category_name category_type
1 engine power battery
1 seats technical
3 release year technical
From searching, people are suggesting that I use union to join these columns. My query now looks like this:
SELECT CARS.car_id
category_id,
CATEGORIES.category_name,
value,
FROM CARS
left join (SELECT BATTERY.battery_category_id AS category_id,
BATTERY.car_id AS car_id,
BATTERY.value AS value
FROM BATTERY
WHERE `BATTERY`.`battery_category_id` IN (1)
UNION
SELECT TECHNICAL_DATA.technical_category_id AS category_id,
TECHNICAL_DATA.car_id AS car_id,
TECHNICAL_DATA.value AS value
FROM TECHNICAL_DATA
WHERE `TECHNICAL_DATA`.`technical_category_id` IN (3))
tt
ON CARS.car_id = tt.car_id
left join CATEGORIES
ON category_id = CATEGORIES.id
So the result I want is this, because I only want to get the data where category_id 1 is in battery table:
car_id category_id category_name technical_value
1 1 engine power 125 kW
1 3 release year 2008
but with the query above I get this, category_id 1 from technical table is included which is not something I want:
car_id category_id category_name value
1 1 engine power 125 kW
1 1 seats 125 kW
1 3 release year 2008
How can get exclude the 'seats' row?
For the results you want, I don't see why the cars table is needed. Then, you seem to need an additional key for the join to categories based on which table it is referring to.
So, I suggest:
SELECT tt.*, c.category_name
FROM ((SELECT b.battery_category_id AS category_id,
b.car_id AS car_id, b.value AS value,
'battery' as which
FROM BATTERY b
WHERE b.battery_category_id IN (1)
) UNION ALL
(SELECT td.technical_category_id AS category_id,
td.car_id AS car_id, td.value AS value,
'technical' as which
FROM TECHNICAL_DATA td
WHERE td.technical_category_id IN (3)
)
) tt LEFT JOIN
CATEGORIES c
ON c.id = tt.category_id AND
c.category_type = tt.which;
That said, you seem to have a problem with your data model, if the join to categories requires "hidden" data such as the type. However, that is outside the scope of the question.

SQL query to return items with count sale_id = 4

I have 3 tables:
user: user_id | user_name
Sale: sale_id(pk) | user_id(fk) | sale_amount
item: item_id(pk) | sale_id(fk)
The sale_id is generated everytime a user purchases from the item table.
I wish to generate an output that will written me user_id, sale_id and count(item_id) i.e, total items purchased by a user in separate transaction where count(sale_id) in item table =4.
I tried using this but it does not work:
select s.user_id,s.id, count(i.item_id)
from sale s join item i
on s.id = i.sale_id
group by s.use_id, i.sale_id
having count(i.sale_id) = 4
;
If a user_id 1 as 2 different transactions where in first transaction(sale_id = 3) he buys 2 items and in second transaction (sale_id = 13) he purchases 4 items which means in the item table each four items purchased will have same sale_id. So, I want to see the output where users have purchased 4 items in one transaction.
output:
s.user_id | i.sale_id | count(i.item_id)
1 13 4
you have aggregation with respect to s.user_id,s.id however you are grouping by s.user_id, i.sale_id. This typically causes error because your query is malformed.
furthermore if you put i.sale_id into group by and try to use having with count(i.sale_id) = 4 this never returns results. because count(i.sale_id) will always be either 0 or 1 when you group by with sale_id

MySQL related items query

I have related products table like this:
product_id | related_product_id
1 | 2
1 | 3
1 | 4
2 | 1
3 | 1
4 | 1
But instead I would like to insert new related product ids so they all match. I.E. If product 1 has 2,3,4 I wan't that products 2,3,4 also have the same related ids which are missing.
Not sure how it's called but is this possible? Many thanks.
You can use a SELECT query as the source of data in an INSERT
INSERT INTO related_products (product_id, related_product_id)
SELECT r1.product_id, r2.related_product_id
FROM related_products AS r1
CROSS JOIN related_products AS r2
WHERE r1.product_id != 1
AND r2.product_id = 1
This join will get all of product 1's related products and combine them with all the other product IDs.
You can give this query a try (untested, make a backup first!):
insert into related_products (product_id,related_product_id) (select related_product_id, product_id from related products);
I would suggest to user bidirectional condition to get the inter related products. For example if you apply condition on single column product_id, you will not get visa-versa result. But, if you check that condition on both column, you will get the result.
For example:
select related_product_id, product_id from products where related_product_id=1 OR product_id=1
This will give your related product id in either related_product_id or product_id.
Same you can get it for product 2 i.e.
select related_product_id, product_id from products where related_product_id=2 OR product_id=2
This will give all your related product id in either related_product_id or product_id.

SQL, Find orders where strict critera is met, Match item, not if other items purchased

I have stumped all the IT people at my work with this one, so wondeirng if anyone can help.
I need to extract from an order table anyone who has only purchased a specific product type, (if they have order the product type and any other product types i dont want to know who you are)
for example the table is roughly
---------------------------------------------------------------------------------------
Order ID | item code | Name |
----------------------------------------------------------------------------------------
1 | ADA | item 1
2 | ADA | item 1
2 | GGG | item 2
3 | ADA | item 1
----------------------------------------------------------------------------------------
So i want to find all the order IDs of people who only purchased item code ADA, BUT not if they purchased over items, so the output of this query should be order ID 1 & 3 and skipping order 2 as this had a different item.
Would really appriciate it if anyone could help.
Assuming an order can't have multiple records with the same ItemCode, you could use:
SELECT *
FROM Orders
WHERE OrderID IN (
SELECT OrderID
FROM Orders
GROUP BY OrderID HAVING COUNT(*) = 1
)
AND ItemCode = 'ADA'
If an order could have multiple records with the same ItemCode then you'd have to change the SELECT * to SELECT DISTINCT * and then COUNT(*) to COUNT(DISTINCT ItemCode)
Based on your current explanation and example, the below should work. However, there are outstanding questions in the comments which may change the actual correct solution.
SELECT
O.OrderId, MAX(itemCode), MAX(Name)
FROM
Orders O
INNER JOIN
(SELECT
OrderId
FROM
Orders
WHERE
itemCode = 'ADA') ADA
ON
O.OrderId = ADA.OrderId
GROUP BY
O.OrderId
HAVING
COUNT(*) = 1

Specific MySQL issue with JOIN

I have a product table:
product_id
shop_id -> id from shop table
product_pair = there is product_id, if it is paired
Then I have a shop table:
shop_id
And finally a shipping table:
shop_id -> id from shop table
country_id -> id of country
And I want to find the products which can be shipped to country_id 60
It's no problem, if it's not paired..
Like:
SELECT p.*, c.*, p.product_name AS score
FROM (`rcp_products` p)
JOIN `rcp_shipping` s ON `s`.`shop_id` = `p`.`shop_id` AND s.country_id = 60
JOIN `rcp_category` c ON `c`.`cat_id` = `p`.`cat_id`
WHERE `p`.`cat_id` = '7'
AND `p`.`product_price_eur` > 0
AND `p`.`product_mark_delete` = 0
ORDER BY `score` asc
LIMIT 10
(There are some additional WHERE's and another columns, which I think haven't got influence)
Now, I have paired products. So, in a table with products is something like this:
product_id | product_name | product_pair | shop_id
1 | Abc | 0 | 0
2 | Def | 1 | 3
3 | Ghi | 1 | 2
So, products 2 and 3 are paired to product 1.
Now, I have no idea how to get country_id for product_id = 1 in that SQL that I posted above.
Maybe my database structure is not the best :) But how can I do it better?
Thank you.
Overall, the idea that you need to use here is self-join - that's how you can find the pairs of products. After that it's just simple WHERE conditions.
The core query (the one that just finds the pairs from a specific shop) would look like this:
SELECT DISTINCT A.product_id as P1, B.product_id as P2, A.shop_id as S1, B.shop_id as S2
FROM products A, products B
WHERE (A.product_pair = B.product_id OR A.product_pair = 0) //find pair and non-paired
AND (A.product_id > B.product_id) //ensure no duplicates (e.g. A&B and B&A)
AND (A.shop_id = B.shop_id) //ensure that both can be found in the same shop
AND A.shop_id = YOUR_SHOP_ID //filter to specific shop
This should satisfy the conditions when products are sold in more than 1 shop, otherwise the query could probably become a bit shorter / easier.