0

I am trying to query a table reviews from a MySQL database. Each row represents a review made on a product. The data for the relevant columns is stored like this:

{ product_id: 25, rating: 1, recommend: 'false' },
{ product_id: 25, rating: 4, recommend: 'true' },
{ product_id: 25, rating: 3, recommend: 'true' },
{ product_id: 25, rating: 2, recommend: 'false' },
{ product_id: 25,  rating: 1, recommend: 'false'}

I need to get the total of each type of rating (eg. how many reviews gave it a ‘1’), and then count how many reviews have recommend ‘true’ and how many have recommend ‘false’. I would like the query to return data like this:

{ product_id: 25, rating: 1, total: 2, recommendTrue: 2, recommendFalse: 3},
{ product_id: 25, rating: 2, total: 1, recommendTrue: 2, recommendFalse: 3},
{ product_id: 25, rating: 3, total: 1, recommendTrue: 2, recommendFalse: 3},
{ product_id: 25, rating: 4, total: 1, recommendTrue: 2, recommendFalse: 3},

Technically I don’t need the recommendTrue and recommendFalse to be on every line, but because I am grouping by the type of rating, the redundancy is fine.

When I use this query (A):

'SELECT product_id, rating, COUNT(rating) as total'
' ' + 'FROM reviews' 
' ' + 'WHERE reviews.product_id = ?' 
' ' + 'GROUP BY rating' 
' ' + 'LIMIT 50'

I get back part of the desired result:

{ product_id: 25, rating: 1, total: 1 },
{ product_id: 25, rating: 3, total: 1 },
{ product_id: 25, rating: 2, total: 3 },
{ product_id: 25, rating: 5, total: 1 },
{ product_id: 25, rating: 4, total: 2 }

I now need to count the total number of True and False recommends amongst all the reviews for product_id 25.

I am trying this query (B):

"SELECT r.product_id, COUNT(r.recommend='false') as F, COUNT(r.recommend='true') as T"
" " + "FROM reviews AS r"
" " + "WHERE r.product_id = ?"
" " + "GROUP BY r.rating"
" " + "LIMIT 50"

And getting this result:

{ product_id: 25, F: 1, T: 1, rating: 1, total: 1 },
{ product_id: 25, F: 1, T: 1, rating: 3, total: 1 },
{ product_id: 25, F: 3, T: 3, rating: 2, total: 3 },
{ product_id: 25, F: 1, T: 1, rating: 5, total: 1 },
{ product_id: 25, F: 2, T: 2, rating: 4, total: 2 }

The recommends need to be counted separately for True and False but should not be counted separately for rating. The way I am writing it, it is counting ALL the recommends (true and false) per rating.

2
  • 1
    Instead of COUNT(r.recommend='false') as F try SUM(CASE WHEN r.recommend='false' THEN 1 ELSE 0 END) as F. Commented Feb 14, 2022 at 6:38
  • The data for the relevant columns is stored like this This value is not correct for MySQL. Provide this as CREATE TABLE + INSERT INTO scripts for unambiguity. Commented Feb 14, 2022 at 6:46

2 Answers 2

2

You have two separate queries: one for the true/false and one for the ratings.

You can combibe the two with a join statement. The query in the join will calculate the true/false and then the result is combined with the ratings query:

select product_id, rating, count(*), t, f
from reviews 
  join (
    select 
      sum(if(recommend='true', 1, 0)) as t, 
      sum(if(recommend='false', 1, 0)) as f
    from reviews
    where product_id=?
  ) as q
where product_id=?
group by product_id, rating, t, f

See db-fiddle.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you so much ! This worked perfectly. I just had to remember to write the query args like this : queryArgs = [productId, productId] so that there would be one for each ? Thank you again for this solution.
1

If you're on MySQL 8+ that supports window functions, you can try with SUM() OVER () function for the base query, then make that as a subquery to do the COUNT() and grouping. Something like this:

SELECT product_id, rating,
       COUNT(product_id) AS total,
       recommendTrue,
       recommendFalse
FROM
(SELECT product_id, rating,
       SUM(recommend='true') OVER () AS recommendTrue,
       SUM(recommend='false') OVER () AS recommendFalse
FROM reviews r
WHERE r.product_id = '25') A
GROUP BY product_id, rating, recommendTrue, recommendFalse

Demo fiddle

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.