Как специалист по SQL, я делал для практики несколько запросов на изменение данных из курса Стэнфорда по SQL. Последнее упражнение было немного сложным для меня, хотя мне удалось его выполнить, используя оператор IN. В качестве небольшого дополнения я попытался переписать запрос, используя EXISTS для подзапроса. Это оказалось сложнее, чем ожидалось, поэтому теперь я задаюсь вопросом, был бы более элегантный способ для этого.
Речь идет о Q4: «Уберите все рейтинги, где год фильма до 1970 года или после 2000 года, а рейтинг меньше 4 звезд».
Упражнения: https://lagunita.stanford.edu/courses/DB/SQL/SelfPaced/courseware/ch-sql/seq-exercise-sql_movie_mod/?activate_block_id=i4x%3A%2F%2FDB%2FSQL%2Fsequential%2Fseq-exercise-sql_movie_mod
Скрипку SQL можно найти здесь: http://www.sqlfiddle.com/#!9/f7f3ad
Заранее большое спасибо!
Сначала я попытался перетащить дополнительный оператор AND в подзапрос и просто заменить IN на EXISTS. Вскоре после того, как я узнал, что это на самом деле удалит всю таблицу, так как предложение Exists будет просто принимать значение true без какой-либо ссылки на внешнюю таблицу.
Поняв это, я попытался использовать псевдоним во внешней таблице, чтобы иметь возможность однозначно ссылаться на внешнюю таблицу изнутри. Однако система не позволит мне сделать это. Я считаю, что они используют Postgres, тогда как мы используем MySQL в Uni. Знаете ли вы, разрешает ли MySQL использовать псевдонимы в операторах изменения данных?
Теперь для самого запроса. Это выглядит довольно многословно для меня. Есть ли более разумный способ сделать это с помощью EXISTS? Или, может быть, что-то совершенно другое, совсем не полагающееся на IN / Exists.
Использование IN:
Delete
FROM Rating
Where MId IN
(
/*movies either before 1970 or after 2000*/
Select r.MId
FROM Movie as m
INNER JOIN Rating as r
on m.MId = r.MId
WHERE m.year <1970 Or m.year > 2000
)
-- pick those with less than 4 stars
AND stars < 4;
Использование Exists:
Delete
FROM Rating
Where EXISTS(
Select *
FROM Movie as m
INNER JOIN Rating as r
on m.MId = r.MId
WHERE (m.year <1970 Or m.year > 2000) AND r.stars < 4
AND Rating.rId = r.RId AND Rating.Mid = r.MId AND Rating.stars <4
);
Одна вещь, из-за которой я боролась, это последний бит, где я проверяю, являются ли звезды во внешней таблице <4. Для меня это выглядит так, будто я выполняю всю работу над запросом только в условии соединения. Тем не менее, я обнаружил, что пропуская это, фактически удалил бы все рейтинги с идентификатором 201, поскольку он находит первый кортеж 201, соответствующий критериям (вне диапазона дат, менее 4 звезд), и пришел к выводу, что, поскольку это существует, он также может удалить другой кортеж (в котором звезды на самом деле> = 4)