mysql joins where unique row required - mysql

I have 2 mysql tables : products and product_images.
products:
product_id price discount product_name
---------------------------------------------------
1 10.00 1.0 product 1
2 20 1.0 product 2
product_images:
product_id images
--------------------------
1 image 1
1 image 2
1 image 3
2 image 1
etc....
I need to select each product_id, price,discount,product_name and only the first image from Product_images. Joins are producing the same product_id repeated with multiple images..
How can i write a query for the same so that product_id is unique with only first image from product_images table ???

try that :
select p.`product_id`, `price`, `discount`, `product_name`,`images`
from products p
inner join product_images pi On p.`product_id` = pi.`product_id`
Where stock_status = 'stock' AND status = 'Enabled'
group by p.`product_id`
DEMO

Yes, you can do this with an aggregate query that takes the "first" image.
SELECT a.product_id, a.price, a.discount, a.product_name, MIN(b.image) AS image
FROM products AS a
LEFT JOIN product_images AS b ON a.product_id = b.product_id
GROUP BY a.product_id, a.price, a.discount, a.product_name
The trick here is that the aggregate MIN() function will find the "first" image.

Something like this?
SELECT p.*,GROUP_CONTACT( pi.images )
FROM product p
LEFT JOIN product_images pi ON pi.product_id = p.product_id
GROUP BY p.product_id
This will give you a comma-separated list of all the images for the product. The problem I see here is you don't seem to currently have a way of defining the "first" image for a product. Maybe you need to add an order column to your product_images table?

As discussed on the comments, here is the query you need:
select product_id, price, discount, product_name, image
from
(select p.product_id,
p.price,
p.discount,
p.product_name,
min(pi.id) im_id
from products p
inner join products_image pi
on (p.product_id=pi.product_id)
group by p.product_id,
p.price,
p.discount,
p.product_name ) pd
inner join
products_image pimg on ( pd.im_id = pimg.id )

Related

MySQL Left join cannot remove duplicates in a single query

I have 2 tables:
products:
- id
- name
product_images:
- id
- image
- product_id
I'm doing the following query:
SELECT p.*, i.image
FROM products p
LEFT JOIN product_images i
ON p.id = i.product_id`
ORDER BY created_at DESC
However if a product has a few images, then this product row is duplicated. How can i remove these duplicates, by showing only the 1st match in a pair of p.id = i.product_id
For this dataset, simple aggregation should do it:
SELECT p.*, min(i.image)
FROM products p
LEFT JOIN product_images i ON p.id = i.product_id
GROUP BY <enumerate all columns from products here>
ORDER BY created_at DESC
LIMIT ${limit}
If you want more colums from product_images, then you can also filter with a correlated subquery; assuming that product_images has primary key id, that would look like:
SELECT p.*, i.image
FROM products p
LEFT JOIN product_images i
ON i.id = (SELECT MIN(i1.id) FROM product_images i1 WHERE i1.product_id = p.id)
ORDER BY created_at DESC
LIMIT ${limit}
If image's data type is varchar or int then instead of joining the table product_images, join to the MIN of the images of each product:
SELECT p.*, i.image
FROM products p
LEFT JOIN (
SELECT product_id, MIN(image) image
FROM product_images
GROUP BY product_id
) i
ON p.id = i.product_id
ORDER BY created_at DESC
LIMIT ${limit}

LEFT JOIN returns NULL if there are just one column in table

I try to get the latest created product price. Every Product is unique but can have different prices. However, my query only works if a product have more than a price as row in the product_price table:
This is my query:
SELECT
i.name AS title,
i.id AS product_id,
m.name AS manufacturer,
image,
price_sales,
price_new,
price_used,
price_old
FROM product_info as i
LEFT JOIN product_manufacturer AS m ON i.manufacturer_id = m.id
LEFT JOIN (SELECT * FROM product_price ORDER BY created_at DESC LIMIT 1) AS p ON i.id = p.id_product
WHERE category_id = 2
AND i.is_deactivated IS NULL
LIMIT 0, 20;
I just need the latest created price row.
Result
The problem you have is that the subquery:
(SELECT * FROM product_price ORDER BY created_at DESC LIMIT 1)
Does not get the latest price per product, but simply the latest price, so will only ever return one row, meaning only one of your products will actually have a price.
The way to resolve this is to remove any prices where a newer one exists, so for simplicity if you look just at the price table, the following will give you only the latest product prices:
SELECT p.*
FROM product_price AS p
WHERE NOT EXISTS
( SELECT 1
FROM product_price AS p2
WHERE p2.id_product = p.id_product
AND p2.created_at > p.created_at
);
However, MySQL will optmise LEFT JOIN/IS NULL better than NOT EXISTS (although I think the former conveys intention better), so a more efficient approach would be:
SELECT p.*
FROM product_price AS p
LEFT JOIN product_price AS p2
ON p2.id_product = p.id_product
AND p2.created_at > p.created_at
WHERE p2.id IS NULL;
Finally, introducing this back to your main query, you would end up with:
SELECT i.name AS title,
i.id AS product_id,
m.name AS manufacturer,
i.image,
p.price_sales,
p.price_new,
p.price_used,
p.price_old
FROM product_info as i
LEFT JOIN product_manufacturer AS m
ON m.id = i.manufacturer_id
LEFT JOIN product_price AS p
ON p.id_product = i.id
LEFT JOIN product_price AS p2
ON p2.id_product = p.id_product
AND p2.created_at > p.created_at
WHERE i.category_id = 2
AND i.is_deactivated IS NULL
AND p2.id IS NULL
LIMIT 0, 20;

return product ids and their count even if there is no variant for them in mysql

i have 3 tables:
table_products - product_id, pname
variants - vid, vname
table_product_varients - product_id, vid
i want to get the count for product variants for all the products, and if there is no variant for a product it should give count as 0.
This is my query:
SELECT P.product_id, count(*) AS count
FROM table_product_varients AS PV
LEFT JOIN table_products AS P ON PV.product_id = P.product_id
GROUP BY P.product_id
ORDER BY P.product_id ASC
But this is not giving products for which there is no variants.
can any one help me on this?
You should have put the table_products table to the left.
Also you should have counted PV.product_id.
SELECT
P.product_id,
count(PV.product_id) AS count
FROM table_products AS P
LEFT JOIN table_product_varients AS PV ON PV.product_id = P.product_id
GROUP BY P.product_id
ORDER BY P.product_id ASC;
Note: For those products which don't have corresponding entry in table_products_varients table you will get NULL value of PV.product_id. Thus COUNT(NULL) actually returns 0
Some subtleties regarding COUNT:
SELECT COUNT(0); Result: 1
SELECT COUNT(-1); Result: 1
SELECT COUNT(NULL); Result: 0
SELECT COUNT(71); Result: 1
SQL FIDDLE

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

mysql count, distinct, join? Confusion

i have 2 tables:
tblItems
ID | orderID | productID
1 1 2
2 1 2
3 2 1
4 3 2
tblProducts
productID | productName
1 ABC
2 DEF
im attempting to find the most popular Product based on whats in "tblItems", and display the product Name and the number of times it appears in the tblItems table.
i can get mysql to count up the total like:
$sql="SELECT COUNT(productID) AS CountProductID FROM tblItems";
but i can't figure out how to join the products table on..if i try LEFT JOIN the query goes horribly wrong
hopefully thats not too confusing..thankss
Are you simply trying to find the count of orders by product like so:
Select P.ProductName, Count(*)
From tblItems As I
Join tblProducts As P
On P.ProductId = I.ProductId
Group By P.ProductName
I think you may be looking for something like:
SELECT tblProducts.productName, COUNT(tblItems.ID)
FROM tblProducts
LEFT JOIN tblItems USING(productID)
GROUP BY tblProducts.productID
SELECT count(i.productID) AS cnt, p.productName FROM tblItems AS i
LEFT JOIN tblProducts AS p ON p.productID = i.productID
GROUP BY i.productID
ORDER BY cnt desc