Group by id, but order by name - mysql

I have a table like this (created from joining different tables)
+------------+--------------+-------------+
| product_id | product_name | category_id |
+------------+--------------+-------------+
| 1 | orange | 3 |
| 1 | orange | 4 |
| 2 | banana | 2 |
| 3 | apple | 2 |
| 3 | apple | 3 |
| 3 | apple | 4 |
+------------+--------------+-------------+
I'd like it grouped together by ID, but sorted by name.
Like this
+------------+--------------+-------------+
| product_id | product_name | category_id |
+------------+--------------+-------------+
| 3 | apple | 2 |
| 3 | apple | 3 |
| 3 | apple | 4 |
| 2 | banana | 2 |
| 1 | orange | 3 |
| 1 | orange | 4 |
+------------+--------------+-------------+
Is this possible? I tried using GROUP BY, but then it only keeps one row per product, so I can't see all the categories a product.
edit: My query so far
SELECT products.id as product_id, products.name as product_name, categories.id as category_id
FROM produkte
LEFT JOIN prod_cat ON products.id = prod_cat.product_id
JOIN categories ON prod_cat.category_id = categories.id
ORDER BY products.id
With "prod_cat" being the table that assigns categories to products.

This will order them by name then category id, giving the results as you have shown them.
SELECT products.id as product_id, products.name as product_name, categories.id as category_id
FROM produkte
LEFT JOIN prod_cat ON products.id = prod_cat.product_id
JOIN categories ON prod_cat.category_id = categories.id
ORDER BY product_name ASC, category_id ASC
I think you've misunderstood GROUP BY, but if you want to group them (reduce records to one where the field given in the GROUP BY clause matches), you can show the categories as a list using GROUP_CONCAT(categories.id) with GROUP BY product_id

Select * from products order by product_id desc, product_name asc;

Related

mysql how do i convert row results to column with new column name?

I have 2 mysql tables that i want to join, but i want the column 'category' results to be in a new column, not rows.
the first one looks something like this
table name = petshop.product
|==========================|
|product_id | product_name |
|==========================|
| 1 | Dog & Cat Toy|
| 2 | Dog Food |
|==========================|
and the second one looks like this
table name = petshop.category
|============================|
|category_id | category_name |
|============================|
| 1 |Dog |
| 2 |Food |
| 3 |Toy |
| 4 |Cat |
|============================|
and i have another table to store the relations that looks like this
table name = petshop.product_category
=================================
|pc_id| product_id | category_id|
|===============================|
| 1 | 1 | 1 |
| 2 | 1 | 3 |
| 3 | 1 | 4 |
| 4 | 2 | 1 |
| 5 | 2 | 2 |
|===============================|
how can i output a table where the result looks like this
|====================================================|
|product_name| category1 | category2 | category3 |
|====================================================|
|Dog&Cat Toy | Dog | Toy | Cat |
|Dog Food | Dog | Food | NULL |
|====================================================|
I read about pivot but i can't wrap my head around it (really new to mysql and coding in general to be honest).
Thank you!
In MySQL 8.0, you can address this with joins, row_number() to enumerate the categories per product, and conditional aggregation to pivot the resultset:
select
product_name,
max(case when rn = 1 then category_name end) category1,
max(case when rn = 2 then category_name end) category2,
max(case when rn = 3 then category_name end) category3
from (
select
p.product_id,
p.product_name,
c.category_name,
row_number() over(partition by p.product_id order by c.category_id) rn
from product p
inner join product_category pc on pc.product_id = p.product_id
inner join category c on c.category_id = pc.category_id
) t
group by product_id, product_name

MySQL: displaying averages or null

I have two tables product and review, some products have reviews, others do not. I want to display the products and for products which have reviews I want to calculate their average rating, if a product has no reviews the average rating should be displayed as null.
Example:
Product:
| Id | Name |
| 1 | dog |
| 2 | cat |
Review:
| Id | Rating|
| 1 | 1 |
| 1 | 5 |
What should be displayed:
| Id | Name | Avg_rating |
| 1 | dog | 3 |
| 2 | cat | NULL |
How can this be achieved?
You can left join, aggregate and round():
select p.id, p.name, round(avg(r.rating)) avg_rating
from product p
left join review r on r.id = p.id
group by p.id, p.name

How to select and count data from three tables in mysql

I have three tables
1 - Products
2- Orders
3- Order_item
Table (Products)
ID | Product_name |
--------------------
1 | Samsung Galaxy
Table (Orders)
ID | Client_name
-------------------
1 | Admin
Table (Orders_item)
ID | Order_ID | Product_ID | Quantity
-------------------------------------
1 | 1 | 1 | 1
2 | 1 | 1 | 1
3 | 1 | 1 | 1
I want to select product name , client name and number of quantities when order is 1. I have tried this query
SELECT products.name,orders.order_id,orders.client_name,order_item.quantity COUNT(*) FROM products,orders,order_item WHERE products.id = order_item.product_id AND orders.order_id = order_item.order_id AND orders.order_id=1
Which returns result like
Name | Order_ID | Client_name | Quantity
----------------------------------------
Sa..| 1 | Admin | 1
Sa..| 1 | Admin | 1
Sa..| 1 | Admin | 1
I want to get the the result like
Samsung | 1 | Admin | 3
Someone please help me .
You need a GROUP BY
SELECT products.Product_name AS Name,
orders.id AS Order_ID,
orders.client_name AS Client_name,
SUM(order_item.Quantity) AS Quantity
FROM products
LEFT JOIN order_item
ON order_item.Product_ID = products.ID
LEFT JOIN orders
ON orders.ID = order_item.Order_ID
WHERE orders.id=1
GROUP BY products.Product_name,
orders.id,
orders.client_name
This outputs :
| Name | Order_ID | Client_name | Quantity |
| -------------- | -------- | ----------- | -------- |
| Samsung Galaxy | 1 | Admin | 3 |
Note that JOIN can be a good reading too.

How to Query for COUNT on a join table and return records with BOTH count=0 AND count>0

I have a Products table and a Reviews table.
I want to write a query to return the COUNT and AVG of the reviews of each product.
AND if there are no reviews I want it to return 0/null for COUNT and AVG.
product table
+--------+----------+
| prodId | prodName |
+--------+----------+
| 1 | apple |
| 2 | banana |
| 3 | cacao |
+--------+----------+
review table
+----------+----------+--------+
| reviewId | prodId | rating |
+----------+----------+--------+
| 1 | 1 | 1 |
| 2 | 1 | 1 |
| 3 | 2 | 5 |
| 4 | 2 | 5 |
+----------+----------+--------+
this is what I want the result to look like:
+--------+----------+--------+-------+
| prodId | prodName | avg | count |
+--------+----------+--------+-------+
| 1 | apple | 1 | 2 |
| 2 | banana | 5 | 2 |
| 3 | cacao | null | 0 |
+--------+----------+--------+-------+
I am able to get the COUNT and AVG for the products with reviews
SELECT p.prodid, p.prodname, avg(r.stars), count(r.productid)
FROM products p
INNER JOIN reviews r ON p.productid=r.productid
GROUP BY p.productid
+--------+----------+--------+-------+
| prodId | prodName | avg | count |
+--------+----------+--------+-------+
| 1 | apple | 1 | 2 |
| 2 | banana | 5 | 2 |
+--------+----------+--------+-------+
I am also able to get the COUNT and AVG for a product with no reviews
SELECT p.prodid, p.prodname, avg(r.stars), count(r.stars)
FROM products p
LEFT OUTER JOIN reviews r
ON (p.productid=r.productid) WHERE r.productid IS NULL
GROUP BY p.productid
+--------+----------+--------+-------+
| prodId | prodName | avg | count |
+--------+----------+--------+-------+
| 3 | cacao | null | 0 |
+--------+----------+--------+-------+
But I don't know if MySql has a way to query and count results that match and count results that have no match in one query.
just remove the where condition from your 2nd query
SELECT p.prodid, p.prodname, avg(r.stars), count(r.stars)
FROM products p
LEFT OUTER JOIN reviews r
ON p.productid=r.productid
GROUP BY p.productid,p.prodname
In practice for MySQL "LEFT JOIN" is the same as LEFT OUTER JOIN. OUTER keyword is optional.
To achieve the result you just need to do simple "LEFT JOIN" and to group by ID (or any other unique key):
SELECT
`p`.`prodId` AS `ID`,
`p`.`prodName` AS `Product`,
avg(`r`.`rating`) AS `AVG Rating`,
count(`r`.`reviewId`) AS `Vote Count`
FROM `products` AS `p`
LEFT JOIN `reviews` AS `r` ON `p`.`prodId` = `r`.`prodId`
GROUP BY `p`.`prodId`

Retrieving last record of a table inside inner join

I have these three tables:
products
+----+--------+
| id | QRCode |
+----+--------+
| 1 | 1000 |
| 2 | 1001 |
+----+--------+
prices
+----+---------+------------+
| id | price | product_id |
+----+---------+------------+
| 2 | $100001 | 1 |
| 3 | $100002 | 1 |
| 4 | $90001 | 2 |
| 5 | $90002 | 2 |
+----+---------+------------+
colors
+----+--------+-------------+
| id | color | product_id |
+----+--------+-------------+
| 1 | ffffff | 1 |
| 2 | f2f2f2 | 1 |
| 4 | aaaaaa | 2 |
| 5 | a3a3a3 | 2 |
+----+--------+-------------+
I would like to merge these three in a way that returns:
group_concat colors based on product_id
retrieves last record of each grouped price
This is the desired output:
+--------+----------------+-------------+-------------+
| QRCode | colors | price | product_id |
+--------+----------------+-------------+-------------+
| 1000 | ffffff, f2f2f2 | $100002 | 1 |
| 1001 | aaaaaa, a3a3a3 | $90002 | 2 |
+--------+----------------+-------------+-------------+
Things I tried:
The query below returns product_id of last record of each grouped price
SELECT product_id FROM price where id IN
(SELECT max(id) FROM price
GROUP BY product_id)
Then I tried to put query above in this query as a subquery
SELECT products.QRCode, priceSubQ.price, GROUP_CONCAT(colors.color) as colors FROM products
INNER JOIN colors on colors.product_id = products.id
INNER JOIN ( /* I put query above here */ ) as priceSubQ ON priceSubQ.product_id = products.id
GROUP BY products.id
What am I doing wrong?
I came across this link which helped me understand the problem
Changed inner query to:
SELECT product_id FROM ANY_VALUE(price) where id IN
(SELECT max(id) FROM price
GROUP BY product_id) group by product_id
solved my problem.
Something like the following should work (not tested)..
SELECT
products.QRCode,
priceSubQ.price,
GROUP_CONCAT(colors.color) as colors
FROM
products
LEFT JOIN colors
ON colors.product_id = products.id
LEFT JOIN (
SELECT
MAX(p1.id) as p1maxId,
p2.price AS price,
p2.product_id AS product_id
FROM
prices p1
INNER JOIN prices p2
ON p1.p1maxId = p2.id
GROUP BY
p1.product_id
) AS priceSubQ
ON priceSubQ.product_id = products.id
GROUP BY
products.id