Can't GROUP BY with first unique item in MYSQL - mysql

I have two MySQL tables:
product
photo
Then I do INNER JOIN
SELECT *
FROM product
INNER JOIN photo
ON product.productID = photo.productID
But I need only one raw per unique product ID
If I try:
SELECT *
FROM product
INNER JOIN photo
ON product.productID = photo.productID
ORDER BY product.productID
It returns error
Expression #38 of SELECT list is not in GROUP BY clause and contains nonaggregated column 'photo.photoID' which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by
The problem is photoID column. There are few photos per one product, but I need table with only first photo per product.
Can I do it with MYSQL tools like WHERE for example?
Thanks!

When you use Aggregate function clause,you need to use GROUP BY on no-Aggregate column.
Making a subquery to find the MIN photoID. then JOIN on another subquery
You can try this.
SELECT p.*,T.* FROM
(
SELECT productID,MIN(photoID) 'photoID'
FROM photo
GROUP BY productID
) T
INNER JOIN (
SELECT DISTINCT productID,name
FROM product
) p ON p.productID = T.productID
sqlfiddle : http://sqlfiddle.com/#!9/97a87d/12

Related

Selecting only last record inside the JOIN statement

I have the following query:
SELECT
usp.user_id AS userId,
usp.create_time AS create_time,
ml.amount AS amount
FROM user_subscription_plan AS usp
RIGHT JOIN product AS product ON product.id = usp.product_id
LEFT JOIN modification_log AS ml ON ml.subscription_id = usp.id
WHERE usp.id IN ('447482')
I have three tables, from which I need to select data.
My problem begins with the last LEFT join.
modification_log table could have no entries, but also it could have more entries.
I want to select only the latest entry. With the above query, if I have 2 (or more) entries in the modification_log, I receive 2 identical results (repeated).
What I would like to get:
If there are no results in the modification_log, then it will return null. I think that is covered with LEFT JOIN. But also, in the case of many record, I would need to select the latest added one (amount)
I believe I might need a sub-query, but I fail to implement it.
You have to use a subquery for taking left join with modification_log table as
SELECT
usp.user_id AS userId,
usp.create_time AS create_time,
ml.amount AS amount
FROM user_subscription_plan AS usp
RIGHT JOIN product AS product ON product.id = usp.product_id
LEFT JOIN
(select * modification_log where subscription_id
IN ('447482') order by created_at desc LIMIT 1)
AS ml ON ml.subscription_id = usp.id
WHERE usp.id IN ('447482')
Note that the where clause in subquery select * modification_log where subscription_id IN ('447482')
is the same as with the last where condition
Just add a max condition after your left join to get the latest entry to be joined, like below-
LEFT JOIN modification_log AS ml ON ml.subscription_id = usp.id
where usp.id IN ('447482') and ml.id = (select max(id) from modification_log)

MYSQL - GROUP BY 2 COLUMN ORDER BY CREATION DATE

I'm trying to get all results of my table with a GROUP BY on 2 columns and get the last insertions.
"Prices" table :
My Request :
SELECT DISTINCT p.*
FROM prices p
JOIN (
SELECT MAX(created_at) as "last_created"
FROM prices
WHERE station_id = 27210003
GROUP BY station_id, fuel_id) as sub
ON sub.last_created = p.created_at
WHERE p.station_id = 27210003
GROUP BY p.station_id, p.fuel_id
Results are 3 lines but wrong line because not last created in my DB -_-'
Please help me !!! >_<'
Thx
Since you're selecting a specific station_id in the WHERE clause, you don't need to include that in GROUP BY.
The subquery has to return the columns you're grouping on, and then you have to include them in the ON clause.
And you don't need GROUP BY in the outer query, since the JOIN should ensure that there's just one row for each fuel_id (unless there are duplicate created_at for the same fuel_id and station_id).
SELECT DISTINCT p.*
FROM prices p
JOIN (
SELECT fuel_id, MAX(created_at) as "last_created"
FROM prices
WHERE station_id = 27210003
GROUP BY fuel_id) as sub
ON sub.last_created = p.created_at AND sub.fuel_id = p.fuel_id
WHERE p.station_id = 27210003

SQL average and Join

I'm trying to merge these two statements into one query to get the a list of product names(or ids) against the average of their TTFF data, and I'm stuck.
select AVG(TTFF) from TTFFdata group by product_id
select product.product_name, count(*) from product join TTFFdata on product.product_id = TTFFdata.product_id
I've looked into using a temporary table (CREATE TEMPORARY TABLE IF NOT EXISTS averages AS (select AVG(TTFF) from TTFFdata group by product_id)) but couldn't get that to work with a join.
Anyone able to help me please?
You need to understand the components. Your second query is missing a group by. This would seem to be what you want:
select p.product_name, count(t.product_id), avg(t.TTFF)
from product p left join
TTFFdata t
on p.product_id = t.product_id
group by p.product_name
It is better to do group by on product_id, product_name for two reasons. One is, you can select product id along with product name. Second reason is, If the product name is not unique then it may give wrong results(this may be a rare scenario like product name is same but it differs based on other columns like version or model). The below is the final query.
select Product.product_id,
product_name,
AVG(TTFF) as Avg_TTFF
from Product
inner join
TTFFdata
on Product.product_id = TTFFdata.product_id
group by Product.product_id,Product.product_name
TTFFdata:
product:
Output:

Filter query by ID

I'm trying to retrieve all the product information, filtering by product category id. The result should be hundreds of products but only returns 5 items. Whats wrong with my query?
SELECT product.id_product,
product.reference,
product.price,
product.active,
product.quantity,
product.id_category_default,
lang.name AS product_name,
lang.description,
lang.link_rewrite AS product_link_rewrite,
category.name AS category_name,
category.link_rewrite AS category_link_rewrite,
image.id_image,
product.id_manufacturer,
discount.reduction,
manufacturer.name AS manufacturer_name
FROM ps_product product
LEFT JOIN ps_specific_price discount ON discount.id_product=product.id_product
LEFT JOIN ps_product_lang lang ON lang.id_product=product.id_product
LEFT JOIN ps_category_lang category ON category.id_category=product.id_category_default
LEFT JOIN ps_image image ON image.id_product=product.id_product
LEFT JOIN ps_manufacturer manufacturer ON manufacturer.id_manufacturer=product.id_manufacturer
WHERE product.active=1
AND product.quantity>=1
AND product.id_category_default IN
(
4,5,6,65,66,90,91,53,54,48,49,50,55,62,67,68,71,19,82,88,89,87,22,24,26,74,
76,77,28,78,79,97,98,99,93,96,35,36,38,39,100
)
GROUP BY product.id_product ASC
Perhaps something as simple as:
GROUP BY product.id_product ASC
needs to be:
ORDER BY product.id_product ASC
mySQL extends the group by clause so that any columns not in the group by may get an indeterminate value.
If ONLY_FULL_GROUP_BY is disabled, a MySQL extension to the standard SQL use of GROUP BY permits the select list, HAVING condition, or ORDER BY list to refer to nonaggregated columns even if the columns are not functionally dependent on GROUP BY columns. ... The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate, which is probably not what you want.
Options:
change group by to order by
add all columns to the group by
don't use group by at all.

Get minimum price with left join / result reduced

I am coding an online shop. A product has a default price, but since it might have different attributes (color, size, ...), those different attributes might result in different prices as well. At the moment I am trying to produce a mysql query which helps me to find the minimum and maximum possible price of a product. Using LEFT JOIN currently reduces the query's result to only one row and I don't know why.
SELECT
products.id AS id,
categories.name AS category_name,
MIN(product_attributes.price) AS min_price, MAX(product_attributes.price) AS max_price,
products.*
FROM products
LEFT JOIN categories ON category_id=categories.id
LEFT JOIN product_attributes ON products.id=product_attributes.product_id
Is this even the correct approach? I do not know that much about mysql, I just try and try and I am happy if it works. Thanks for help anyway.
You are missing a GROUP BY clause in your current query, but I would recommend using a subquery to get the result:
SELECT
p.id AS id,
c.name AS category_name,
pa.min_price,
pa.max_price,
p.*
FROM products p
LEFT JOIN categories c
ON p.category_id = c.id
LEFT JOIN
(
select MIN(product_attributes.price) min_price,
MAX(product_attributes.price) max_price,
product_id
from product_attributes
group by product_id
) pa
ON p.id=pa.product_id
The main reason why I would suggest using a subquery is because MySQL MySQL uses a EXTENSION TO GROUP BY which allows the behavior of not enforcing the FULL GROUP BY.
This extension in MySQL can cause unexpected values to be returned in the columns in the SELECT list that are not in the GROUP BY clause or in an aggregate function.
From the MySQL Docs:
MySQL extends the use of GROUP BY so that the select list can refer to nonaggregated columns not named in the GROUP BY clause. ... You can use this feature to get better performance by avoiding unnecessary column sorting and grouping. However, this is useful primarily when all values in each nonaggregated column not named in the GROUP BY are the same for each group. The server is free to choose any value from each group, so unless they are the same, the values chosen are indeterminate. Furthermore, the selection of values from each group cannot be influenced by adding an ORDER BY clause. Sorting of the result set occurs after values have been chosen, and ORDER BY does not affect which values the server chooses.
you need to have GROUP BY clause,
SELECT
products.id AS id,
categories.name AS category_name,
MIN(product_attributes.price) AS min_price,
MAX(product_attributes.price) AS max_price.
products.*
FROM products
LEFT JOIN categories ON category_id=categories.id
LEFT JOIN product_attributes ON products.id=product_attributes.product_id
GROUP BY products.id, categories.name
but be careful when using GROUP BY in mysql, as the statement is perfectly valid if ONLY_FULL_GROUP_BY is disabled by default.
The correct way of doing the query is by using a subquery which separately gets minimum price for each product.
SELECT a.id AS id,
b.name AS category_name,
c.minPrice,
c.maxPrice,
a.*
FROM products a
LEFT JOIN categories b
ON a.category_id = b.id
LEFT JOIN product_attributes c
(
SELECT product_id,
MIN(product_attributes.price) minPrice,
MAX(product_attributes.price) maxPrice
FROM product_attributes
GROUP BY product_id
) d ON a.id = c.product_id