How to make a "distinct" join with MySQL - mysql

I have two MySQL tables (product and price history) that I would like to join:
Product table:
Id = int
Name = varchar
Manufacturer = varchar
UPC = varchar
Date_added = datetime
Price_h table:
Id = int
Product_id = int
Price = int
Date = datetime
I can perform a simple LEFT JOIN:
SELECT Product.UPC, Product.Name, Price_h.Price, Price_h.Date
FROM Product
LEFT JOIN Price_h
ON Product.Id = Price_h.Product_id;
But as expected if I have more than one entry for a product in the price history table, I get one result for each historical price.
How can a structure a join that will only return one instance of each produce with only the newest entry from the price history table joined to it?

Use:
SELECT p.upc,
p.name,
ph.price,
ph.date
FROM PRODUCT p
LEFT JOIN PRICE_H ph ON ph.product_id = p.id
JOIN (SELECT a.product_id,
MAX(a.date) AS max_date
FROM PRICE_H a
GROUP BY a.product_id) x ON x.product_id = ph.product_id
AND x.max_date = ph.date

SELECT Product.UPC, Product.Name, Price_h.Price, Price_h.Date
FROM Product
LEFT JOIN Price_h
ON (Product.Id = Price_h.Product_id AND Price_h.Date =
(SELECT MAX(Date) FROM Price_h ph1 WHERE ph1.Product_id = Product.Id));

Try this:
SELECT Product.UPC, Product.Name, Price_h.Price, MAX(Price_h.Date)
FROM Product
INNER JOIN Price_h
ON Product.Id = Price_h.Product_id
GROUP BY Product.UPC, Product.Name, Price_h.Price

SELECT n.product_id,
n.product_name,
n.product_articul,
n.product_price,
n.product_discount,
n.product_description,
n.product_care,
(SELECT photo_name FROM siamm_product_photos WHERE product_id = n.product_id LIMIT 1) AS photo_name
FROM siamm_product as n;

Why not keep it simple and fast:
SELECT
Product.UPC, Product.Name, Price_h.Price, Price_h.Date
FROM
Product
LEFT JOIN
Price_h
ON Product.Id = Price_h.Product_id;
ORDER BY
Price_h.Date DESC
LIMIT 1

Related

How to select multiple MIN record of table that inner joinned with other 3 table based on other table parameter(s)?

I have a question. I have 4 tables:
product_list
product
product_img
pricelist
This what my query looks like:
SELECT
product_list.id,
product_list.class,
product.prod_name,
product.prod_url,
product.prod_overview,
product_img.list_prod340x340,
pricelist.price
FROM
(
(
(
product_list
INNER JOIN product ON product_list.id = product.prod_list_id
)
INNER JOIN product_img ON product.id = product_img.prod_id
)
INNER JOIN pricelist ON product.id = pricelist.prod_id
)
ORDER BY product_list.id, pricelist.price ASC
This is the result of the query
[QUERY RESULT]
[1]: https://i.stack.imgur.com/V9JO1.jpg
So the question is, how can i get only the lowest price of each prod_name.
This is how it should be returned
id
...
prod_name
...
...
...
price
1
...
Toyota Agya
...
...
...
155500000
2
...
Toyota Calya
...
...
...
151600000
please help?
Please test this:
SELECT product_list.id, product_list.class,
product.prod_name, product.prod_url,
product.prod_overview, product_img.list_prod340x340, MIN(pricelist.price)
FROM (((product_list
INNER JOIN product
ON product_list.id = product.prod_list_id)
INNER JOIN product_img
ON product.id = product_img.prod_id)
INNER JOIN pricelist
ON product.id = pricelist.prod_id)
GROUP BY product_list.id, product_list.class, product.prod_name, product.prod_url,product.prod_overview, product_img.list_prod340x340
ORDER BY product_list.id, pricelist.price ASC
The easiest approach is probably to get the price in a subquery:
SELECT
pl.id,
pl.class,
p.prod_name,
p.prod_url,
p.prod_overview,
pi.list_prod340x340,
(
SELECT MIN(price)
FROM pricelist prl
WHERE prl.price = p.id
) AS min_price
FROM product_list pl
INNER JOIN product p ON p.prod_list_id = pl.id
INNER JOIN product_img pi ON pi.prod_id = p.id
ORDER BY pl.id, p.id;
Since MySQL 8.0.14 you can move the subquery to the FROM clause and make this a lateral join, which allows you to select more than one column from the price table:
SELECT
pl.id,
pl.class,
p.prod_name,
p.prod_url,
p.prod_overview,
pi.list_prod340x340,
prli.price
FROM product_list pl
INNER JOIN product p ON p.prod_list_id = pl.id
INNER JOIN product_img pi ON pi.prod_id = p.id
CROSS JOIN LATERAL
(
SELECT *
FROM pricelist prl
WHERE prl.price = p.id
ORDER BY prl.price
LIMIT 1
) prli
ORDER BY pl.id, p.id;

i want to get lowest price values with id in mysql

my query is
SELECT productscrapeddatalog.*, product.productname
FROM productscrapeddatalog JOIN product
ON productscrapeddatalog.productID = product.productID
WHERE price = (SELECT MIN(price) FROM productscrapeddatalog ORDER BY productID)
this is my table screenshot
Your approach with a join and filtering in the where clause is ok - but you need to correlate the subquery with the outer query so you get the lowest price per product rathern thatn the overall min:
SELECT l.*, p.productname
FROM productscrapeddatalog l
JOIN product p ON l.productID = l.productID
WHERE l.price = (
SELECT MIN(l1.price)
FROM productscrapeddatalog l1
WHERE l1.productID = t.productID
)
If you are running MySQL 8.0, you can also do this with window functions:
SELECT l.*, p.productname
FROM product p
JOIN (
SELECT l.*, RANK() OVER(PARTITION BY productID ORDER BY price) rn
FROM productscrapeddatalog l
) p ON l.productID = l.productID AND l.rn = 1
You should try this:
SELECT productscrapeddatalog.*, product.productname, MIN(productscrapeddatalog.price)
FROM productscrapeddatalog JOIN product
ON productscrapeddatalog.productID = product.productID
ORDER BY productID

select sum qty from 2 tables

In MySQL I have 4 tables:
- product(id)
- order(id)
- order_detail_1(id, product_id, order_id, qty)
- order_detail_2(id, product_id, order_id, qty)
I want to get the sum of the quantity of products sold from the 2 tables (order_detail_1, order_detail_2) grouping them by product
produt can existe in order_detail_1 and not in order_detail_2 and vice versa
i tested this query and it worked but I want a simpler query without the union and the subquery.
select tmp.product_id ,sum(tmp.qty) from
(
(
select order_detail_1.product_id ,sum(order_detail_1.qty)
from order_detail_1
inner join order on order_detail_1.id_order = order.id
where order_detail_1.product_id is not null
group by order_detail_1.product_id
)
union all
(
select order_detail_2.product_id ,sum(order_detail_2.qty)
from order_detail_2
inner join order on order_detail_2.id_order = order.id
where order_detail_2.product_id is not null
group by order_detail_2.product_id
)
) tmp
group by tmp.product_id
It looks like you're not using order table other then checking if it exists, so you can use EXISTS()
SELECT p.product_id,sum(p.qty) as qty
FROM (SELECT product_id,qty,id_order FROM order_detail_1
WHERE product_id IS NOT NULL
UNION ALL
SELECT product_id,qty,id_order FROM order_detail_2
WHERE product_id IS NOT NULL) p
WHERE EXISTS(SELECT 1 FROM order o
WHERE o.id = p.id_order)
GROUP BY p.product_id
If a product is in only one table, you can use left join:
select p.id, (coalesce(sum(od1.qty), 0) + coalesce(sum(od2.qty, 0))) as qty
from product p left join
order_detail_1 od1
on od1.product_id = p.id left join
order_detail_2 od2
on od2.product_id = p.id
group by p.id;
This formulation depends on the fact that the two tables are exclusion -- a product is in only one table.
EDIT:
If products can exist in both tables, then you need to aggregate them first:
select p.id, (coalesce(od1.qty, 0) + coalesce(od2.qty, 0)) as qty
from product p left join
(select product_id, sum(qty) as qty
from order_detail_1 od1
group by product_id
) od1
on od1.product_id = p.id left join
(select product_id, sum(qty) as qty
from order_detail_2 od2
group by product_id
) od2
on od2.product_id = p.id;

MYSQL NOT IN with multiple column names

i have 2 mysql queries,
1 is to select the all branch stocks and other is to select stock count lists.
i need to select all the branch stocks which is not included in stock count lists( by considering stock barcode and stock batch)
my first query to select all branch stock is
SELECT SQL_CALC_FOUND_ROWS stock_id ,product_name , stock_batch,stock_barcode
FROM stock INNER JOIN product ON product_id = stock_product
LEFT JOIN packing ON product_package=packing_id
WHERE stock_branch = 2 AND stock_available_flg = 1
group by stock_id
and second query to select counted stock lists is
SELECT SQL_CALC_FOUND_ROWS stock_id,stock_barcode, product_name,stock_batch FROM stock_count_item
INNER JOIN stock ON stock_id = stock_count_item_stock
INNER JOIN product ON stock_product = product_id
INNER JOIN category ON category_id = product_category
WHERE stock_count_item_stock_count = 42 GROUP BY stock_barcode
what i need is to select all branch stock which is not included in stock count lsts with same barcode and batch
my query is
SELECT SQL_CALC_FOUND_ROWS stock_id ,product_name , stock_batch,stock_barcode
FROM stock
INNER JOIN product ON product_id = stock_product
LEFT JOIN packing ON product_package=packing_id
WHERE stock_branch = 2 AND stock_available_flg = 1 AND ( stock_batch,stock_barcode)
not in
(SELECT stock_batch ,stock_barcode FROM stock_count_item
INNER JOIN stock ON stock_id = stock_count_item_stock
INNER JOIN product ON stock_product = product_id
INNER JOIN category ON category_id = product_category WHERE stock_count_item_stock_count = 42)
but this not gives the correct result .How am consider stock_batch,stock_barcode together to correct this?
Use NOT EXISTS instead of NOT IN
BUT because you have not identified which tables each column comes from so I (or anyone maintaining your code) cannot learn a column's source from reading the query. ALWAYS prefix the column by the table (or table's alias).
SELECT
SQL_CALC_FOUND_ROWS stock_id
, product_name
, stock_batch
, stock_barcode
FROM stock
INNER JOIN product ON product_id = stock_product
LEFT JOIN packing ON product_package = packing_id
WHERE stock_branch = 2
AND stock_available_flg = 1
NOT NOT EXSTS (
SELECT 1
FROM stock_count_item
INNER JOIN stock ON stock_id = stock_count_item_stock
INNER JOIN product ON stock_product = product_id
INNER JOIN category ON category_id = product_category
WHERE stock_count_item_stock_count = 42
and outer_alias.stock_batch = inner_alias.stock_batch
and outer_alias.stock_barcode = inner_alias.stock_barcode
)
;
I have tried to indicate what is required by using
and outer_alias.stock_batch = inner_alias.stock_batch
the "outer_alias" is an alias (or tablename) from before the NOT EXISTS subquery, and the inner_alias is the reverse. At least one of these has to be an alias if you choose to use a tablename for one of hem.
e.g.
select ... from stock where not exists (... from stock s and stock.id = s.id)
"stock" is the "outer_alias" of stock.id
"s" is the "inner_alias" of s.id
the final query with aliases (via comment below)
SELECT
SQL_CALC_FOUND_ROWS stock_id
, product_name
, s.stock_batch --<< please please please use aliases everywhere
, s.stock_barcode
FROM stock s
INNER JOIN product ON product_id = stock_product
LEFT JOIN packing ON product_package = packing_id
WHERE stock_branch = 2
AND stock_available_flg = 1
AND NOT EXISTS (
SELECT
1
FROM stock_count_item
INNER JOIN stock st ON stock_id = stock_count_item_stock
INNER JOIN product ON stock_product = product_id
INNER JOIN category ON category_id = product_category
WHERE stock_count_item_stock_count = 42
AND s.stock_batch = st.stock_batch
AND s.stock_barcode = st.stock_barcode
)

Select from 3 tables with two order by before two group by

I try to get a list of products with each newest and lowest offer price
Table product:
id | name
Table offer:
id | product_id | price | created | dealer_id
Table invalids:
id | offer_id | status
I have tried:
SELECT * FROM product INNER JOIN
(
SELECT offer.product_id , offer.price
FROM offer
LEFT JOIN invalids
ON offer.id = invalids.offer_id
WHERE invalids.id IS NULL
GROUP BY offer.dealer_id
ORDER BY offer.created DESC
) o
ON o.product_id = product.id
ORDER BY product.name
I have tried an sqlfiddle http://sqlfiddle.com/#!9/32658/3 with this offer values:
(`id`, `price`, `dealer_id`, `product_id`, `created`)
(1,12.60,1,1,'2015-05-17 08:44:45'),
(2,13.00,1,1,'2015-08-17 08:44:45'),
(3,20.00,1,1,'2015-08-17 08:45:30'),
(4,10.00,1,1,'2015-08-17 08:45:46'),
(5,4.00,2,1,'2015-05-17 08:44:11'),
(6,11.00,2,1,'2015-08-17 08:44:46'),
(7,5.00,2,1,'2015-08-17 08:45:31'),
(9,110.00,2,2,'2015-08-17 08:46:58'),
(10,11.00,2,2,'2015-08-17 08:47:12');
Expected value for product ID 1 is offer ID 7 with price 5.
These steps I think I must realize:
Order offers by created and group by dealer_id to get newest entries
Take result from step 1 and order it by price to get smallest price.
Make this for all products
Maybe I must use a second SELECT FROM offer with GROUP BY and ORDER BY but how do I get I the product_id from the first (outer) select?
Well I would start by getting the latest date for each product offer like this:
SELECT product_id, MAX(created) AS latestOffer
FROM offer
GROUP BY product_id;
Once you have that, you can join it to the original table to get that offer:
SELECT o.*
FROM offer o
JOIN(
SELECT product_id, MAX(created) AS latestOffer
FROM offer
GROUP BY product_id) tmp ON tmp.product_id = o.product_id AND tmp.latestOffer = o.created;
Here is an SQL Fiddle example.
This query should help you:
SELECT *
FROM product
JOIN (
SELECT product_id, min(price) as minPrice, max(created) as newestOffer
FROM offer
WHERE id NOT IN (SELECT offer_id FROM invalids)
GROUP BY 1
) as b
ON product.id = b.product_id
A shot in the dark based on what I understand you to be after...
lots of nested subqueries.. keep thinking there's got to be a better way...
SELECT OO.ID, OO.Price, OO.Dealer_Id, OO.Product_ID, OO.created, P.name
FROM Offer OO
INNER JOIN (
SELECT Min(Price) as MinP
FROM offer O
INNER JOIN (
SELECT max(OI.created) as LatestOffer, OI.Dealer_ID, OI.Product_ID
FROM Offer OI
LEFT JOIN invalids I
on OI.Id = I.offer_Id
WHERE I.ID is null
GROUP BY OI.Dealer_Id, OI.Product_Id
) B
on O.Dealer_Id = B.Dealer_Id
and O.Product_Id = B.Product_Id
and O.Created = B.LatestOffer
) Z
on OO.Price = Z.MinP
INNER JOIN product P
on P.ID = OO.Product_ID
SQL FIDDLE