【问题标题】:Using EXISTS instead of IN operator in delete-statement with subquery在带有子查询的删除语句中使用 EXISTS 而不是 IN 运算符
【发布时间】:2019-06-05 10:15:34
【问题描述】:

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

大约是第 4 季度:“删除电影年份在 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 fiddle 可以在这里找到:http://www.sqlfiddle.com/#!9/f7f3ad

非常感谢您!

我首先尝试将附加的 AND 语句拖到子查询中,然后仅将 IN 替换为 EXISTS。不久之后,我发现这实际上会删除整个表,因为 Exists 子句将评估为 true,而无需任何外部表的引用。

意识到这一点后,我尝试在外部表中使用别名,以便能够从内部明确引用外部表。但是,系统不允许我这样做。我相信他们正在运行 Postgres,而我们在 Uni 使用 MySQL。你知道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;

使用存在:

 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)

【问题讨论】:

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


    【解决方案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;
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2019-04-05
        • 2014-07-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-06-04
        • 2021-06-21
        • 2015-01-30
        • 1970-01-01
        相关资源
        最近更新 更多