Skip to content
Advertisement

How do I remove results based on conditions to calculate an average

I have the schema below. A quick explanation of it is:

  1. bob rated up 5/5
  2. james rated up 1/5
  3. macy rated up 5/5

The logic:

  1. If I am personA, look up everyone I have blocked.
  2. Look up all the movie reviews.
  3. Anyone who has left a movie review, and personA has blocked, remove them from the calculation.
  4. Calculate the average rating of the movies.

CREATE TABLE movies (
  id integer AUTO_INCREMENT primary key,
  name varchar(100) NOT NULL
);

CREATE TABLE customer (
  id integer AUTO_INCREMENT primary key,
  name varchar(100) NOT NULL
);

CREATE TABLE reviews (
  id integer AUTO_INCREMENT primary key,
  rating integer NOT NULL,
  cus_id integer NOT NULL,
  movie_id integer NOT NULL,
  FOREIGN KEY (cus_id) REFERENCES customer(id),
  FOREIGN KEY (movie_id) REFERENCES movies(id)
);

CREATE TABLE blocked(
  id integer AUTO_INCREMENT primary key,
  cus_id integer NOT NULL, -- This is the person blocking
  blocked_cus_id integer NOT NULL, -- This is the person who is blocked
  FOREIGN KEY (cus_id) REFERENCES customer(id),
  FOREIGN KEY (blocked_cus_id) REFERENCES customer(id)
);

INSERT INTO movies (id, name) VALUES (1, 'up');
INSERT INTO customer (id, name) VALUES (1, 'bob'), (2, 'james'), (3, 'macy');
INSERT INTO reviews (id, rating, cus_id, movie_id) VALUES (1, 5, 1, 1), (2, 1, 2, 1), (3, 5, 3, 1);
INSERT INTO blocked (id, cus_id, blocked_cus_id) VALUES (1, 1, 2);

I don’t understand how I can get rid of reviews if its on a block list

SELECT m.name, avg(r.rating) as avg_rating
FROM movies m
JOIN reviews r ON m.id = r.movie_id
JOIN blocked b on r.cus_id = b.blocked_cus_id
WHERE b.cus_id = 1 -- Viewing the database as bob

When I view the database as bob, I should get:

+-------+------------+
| movie | avg_rating |
+-------+------------+
| up    |          5 |
+-------+------------+

When I view the database as macy, I should get:

+-------+------------+
| movie | avg_rating |
+-------+------------+
| up    |       3.67 |
+-------+------------+

Advertisement

Answer

I don’t know how to express your logic without using an exists clause. I might try here:

SELECT m.name, AVG(r.rating) AS avg_rating
FROM movies m
INNER JOIN reviews r ON m.id = r.movie_id
WHERE NOT EXISTS (SELECT 1 FROM blocked b
                  WHERE b.blocked_cus_id = r.cus_id AND b.cus_id = 1)
GROUP BY m.name;

Note that we want to aggregate by movie name, so we need GROUP BY here. The exists clause says to exclude from the average rating any review for which we can find a blocked entry belonging to a certain customer (in this case, cus_id = 1).

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement