【问题标题】:How to resolve this SQL query?如何解决这个 SQL 查询?
【发布时间】:2014-08-07 21:21:19
【问题描述】:

作为斯坦福数据库 MOOC 中包含的练习,我在使用此查询时遇到问题:

对于同一评论者对同一部电影两次评分并第二次给予更高评分的所有情况,返回评论者的姓名和电影的标题。

本练习使用了三个表格:movie, rating and reviewer。正在使用的系统是SQLite

movie;
+----------+---------+------+-----+---------+-------+
| Field    | Type    | Null | Key | Default | Extra |
+----------+---------+------+-----+---------+-------+
| mID      | int(11) | YES  |     | NULL    |       |
| title    | text    | YES  |     | NULL    |       |
| year     | int(11) | YES  |     | NULL    |       |
| director | text    | YES  |     | NULL    |       |
+----------+---------+------+-----+---------+-------+

rating;
+------------+---------+------+-----+---------+-------+
| Field      | Type    | Null | Key | Default | Extra |
+------------+---------+------+-----+---------+-------+
| rID        | int(11) | YES  |     | NULL    |       |
| mID        | int(11) | YES  |     | NULL    |       |
| stars      | int(11) | YES  |     | NULL    |       |
| ratingDate | date    | YES  |     | NULL    |       |
+------------+---------+------+-----+---------+-------+

reviewer;
+-------+---------+------+-----+---------+-------+
| Field | Type    | Null | Key | Default | Extra |
+-------+---------+------+-----+---------+-------+
| rID   | int(11) | YES  |     | NULL    |       |
| name  | text    | YES  |     | NULL    |       |
+-------+---------+------+-----+---------+-------+

Expected Query Result:
name            title         
Sarah Martinez  Gone with the Wind

如果有人也想要数据,here it is

【问题讨论】:

  • 到目前为止你有没有尝试过?对于这个查询,您考虑了哪些方面?
  • 你到底有什么“麻烦”?
  • 我想了很多,我知道如何获得对同一部电影两次评分的评论者,但我不知道如何应用条件“并给它第二次更高的评分”
  • @DourHighArch 看看上面的评论,问题在于查询的逻辑结构,如果我掌握了步骤,我猜语法不会是问题

标签: sql sqlite


【解决方案1】:
SELECT
   W.name,
   M.title
FROM
   reviewer AS R
   INNER JOIN movie AS M
      ON EXISTS ( -- there is at least one rating
         SELECT *
         FROM rating AS G
         WHERE
            -- by the reviewer and movie in question
            R.rID = G.rID
            AND M.mID = G.mID
            AND EXISTS ( -- for which another rating exists
               SELECT *
               FROM rating AS G2
               WHERE
                  -- for the same reviewer and movie
                  R.rID = G2.rID
                  AND M.mID = G2.mID
                  AND G.stars < G2.stars -- but rated higher
                  AND G.ratingDate < G2.ratingDate -- and later
            )
      )
;

我不能 100% 确定 SQLite 是否允许 ON 子句具有 EXISTS 表达式。如果没有,您可以将EXISTS 表达式移动到WHERE 子句并在reviewermovie 之间执行交叉连接。

如果 SQLite 不支持EXISTS,则将EXISTS 查询作为派生表放在FROM 子句中,两个表INNER JOIN 相互连接,然后GROUP BY @ 987654333@ 和 rID,然后 INNER JOIN 到主表。可能看起来像这样:

SELECT
   R.name,
   M.title
FROM
   (
      SELECT
         G.rID,
         G.mID
      FROM
         rating AS G
         INNER JOIN rating AS G2
            ON G.rID = G2.rID
            AND G.mID = G2.mID
            AND G.stars < G2.stars
            AND G.ratingDate < G2.ratingDate
      GROUP BY
         G.rID,
         G.mID
   ) C
   INNER JOIN reviewer AS R
      ON C.rID = R.rID
   INNER JOIN movie AS M
      ON C.mID = R.mID
;

我希望您能看到这两个查询如何表达相同的语义。在一个非常大的数据库中,人们对同一部电影进行了多次评分,可能会存在性能差异(我第一次展示的EXISTS 版本可能表现更好,因为它可以在找到一个结果后立即停止)。

注意:您可以将整个混乱合并到一个查询中,并将GROUP BYnametitlerIDmID,但是虽然“更简单”,但这会更错误,因为无需为许多行重复名称和标题,只需通过分组丢弃该信息。分组应尽早进行。

【讨论】:

  • 这行得通,谢谢,但对我来说太复杂了,您认为这是最短的解决方案还是有更简单的解决方案?不过还是谢谢
  • 在许多方面,这是最简单的解决方案。其他解决方案需要体操来摆脱它们导致的行重复。我会努力为你展示一个“更简单”的版本。
  • 我检查了第一个查询,现在完全理解了。正如你所说,第二个似乎更复杂,需要更多时间。感谢您的完整解释,如果可以的话,我会投不止一个赞成票。
  • 您可以单击我的答案旁边的大复选标记按钮,这会将我的答案标记为您接受的答案(这会给我更多的分数)。谢谢!
【解决方案2】:

我已经设法用这个查询解决了这个特定的练习:

SELECT R.name, M.title
FROM
    Rating AS RatingLatest
JOIN Rating AS R2 
    ON RatingLatest.rID = R2.rID AND R1.mID = R2.mID
JOIN Reviewer AS R USING (rID)
JOIN Movie AS M USING (mID)
-- Check if there is a newer rating with more stars than the previous one 
WHERE RatingLatest.ratingDate > R2.ratingDate 
AND RatingLatest.stars > R2.stars 

它返回对同一部电影多次评分的评论者,以及最后一次(不是特别是第二次)评分更高的评论。

【讨论】:

  • 您可以通过写下几个 cmets 来改进您的答案,您可以在其中指定 R1 表是最新评级还是 R2 是。
  • @SrijanChaudhary 我已经更新了我的答案,现在更好了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-03
  • 2021-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-03
相关资源
最近更新 更多