在子查询的删除语句中使用EXISTS代替IN运算符

时间:2019-06-05 10:15:34

标签: mysql sql sql-delete exists in-operator

作为一名SQL外行,我从Stanford的SQL课程进行一些数据修改查询以进行练习。尽管我设法使用IN运算符完成了最后一个练习,但对我来说还是有些棘手。作为一个小插件,我尝试为子查询使用EXISTS重写查询。事实证明,这比预期的要难,所以现在我想知道是否会有更优雅的方法。

大约是在第四季度:“删除电影年份在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-clause会在不引用外部表的情况下评估为true。

意识到这一点,我尝试在外部表中使用Alias,以便能够从内部明确引用外部表。但是,系统不允许我这样做。我相信他们正在运行Postgres,而我们正在Uni上使用MySQL。您知道MySQL是否允许在数据修改语句中使用别名吗?

现在查询本身。在我看来,它很冗长。是否存在使用EXISTS进行此操作的更明智的方法?或者也许完全不依赖IN /存在的东西完全不同。

使用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;

使用存在的内容

 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的最后一点。对我来说,我似乎在联接条件内完成整个查询的工作。但是,我发现不进行此操作实际上会删除rId 201的所有评分,因为它发现符合条件的前201个元组(超出日期范围,少于4星),并得出结论,既然存在,它也可以删除另一个元组(其中的星星实际上> = 4)

2 个答案:

答案 0 :(得分:1)

在这样的语句中,MySQL不允许您引用正在更新或删除的表。就您而言,这很容易解决。

我更喜欢exists

delete r from rating r
where exists (select 1
                from Movie m
                where m.MId = r.MId and
                      (m.year < 1970 or m.year > 2000)
             ) and
-- pick those with less than 4 stars
     r.stars < 4;

您可以使用in做类似的事情:

delete r from rating r
where r.MId in (select m.MId
                from Movie m
                where m.year < 1970 or m.year > 2000
             ) and
-- pick those with less than 4 stars
     r.stars < 4;

答案 1 :(得分:0)

使用JOIN

的简单替代方法
DELETE r FROM Rating r
INNER JOIN Movie m ON r.mID=m.mID 
WHERE r.stars<4 AND (m.year<1970 OR m.year>2000);