如何解决这个SQL查询?

时间:2014-08-07 21:21:20

标签: sql sqlite

我将此查询作为练习包含在斯坦福数据库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

1 个答案:

答案 0 :(得分:2)

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 mIdrID,然后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 BY nametitlerIDmID,但同时& #34;更简单&#34;,这将更加错误,因为不需要复制许多行的名称和标题,只是通过分组丢弃该信息。分组应该尽早发生。