问题
I have the schema below. A quick explanation of it is:
- bob rated up 5/5
- james rated up 1/5
- macy rated up 5/5
The logic:
- If I am personA, look up everyone I have blocked.
- Look up all the movie reviews.
- Anyone who has left a movie review, and personA has blocked, remove them from the calculation.
- 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 |
+-------+------------+
回答1:
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
).
来源:https://stackoverflow.com/questions/64763062/how-do-i-remove-results-based-on-conditions-to-calculate-an-average