【问题标题】:SQL query over three tables对三个表的 SQL 查询
【发布时间】:2013-06-17 22:10:51
【问题描述】:

我必须为我的学校创建一个数据库,现在我有这三个表:

Note                               Examination               Subject
+------+------+------+--------+    +------+----+--------+    +------+----------+
| _idS | _idP | Note | Punkte |    | _idP | idF| Thema  |    | _idF |   Name   |
+------+------+------+--------+    +------+----+--------+    +------+----------+
|    1 |    2 |    4 |     55 |    |    1 |  2 | Test 1 |    |    1 | Englisch |
|    2 |    2 |    2 |     80 |    |    2 |  4 | Test 2 |    |    2 | Deutsch  |
|    3 |    2 |    1 |     95 |    |    3 |  4 | Test 3 |    |    3 | Mathe    |
|    1 |    3 |    1 |     90 |    +------+----+--------+    |    4 | Physik   |
+------+------+------+--------+                              +------+----------+

现在我想从Name 给出的特殊科目和他的ID (_idS) 给出的特殊学生中选择所有Notes。我尝试过这样的事情:

SELECT N._idP, N.Note, N.Punkte, E.Thema FROM Note N, Examination E 
WHERE  N._idS='1' AND N._idP=(
       SELECT E._idP FROM Examination E WHERE E.idF=(
              SELECT S._idF FROM Subject S WHERE S.Name='Physik')
       );

// N._idS=1 is the special pupil
// S.Name='Physik' is the special subject

但这不会导致正确的输出。为了更清楚一点:我想要这个输出:

+--------+--------+----------+---------+
| N._idP | N.Note | N.Punkte | E.Thema |
+--------+--------+----------+---------+
|      2 |      4 |       55 | Test 2  |
|      3 |      1 |       90 | Test 3  |
+--------+--------+----------+---------+

我的 SQL 语句有什么问题,我必须更改什么才能获得上述结果? 所有开头带下划线_ 的列名都是PRIMARY KEYS。其他都是FOREIGN KEYS

【问题讨论】:

  • ID (_diS) 还是ID (_idS)
  • 它是ID (_idS)。改进了谢谢。
  • 您使用的是什么 DBMS?这可能无关紧要,但知道总是有帮助的。
  • 我在 Android 上使用 SQLite

标签: sql sqlite android-sqlite


【解决方案1】:

您的查询有什么问题首先是没有关联外部NoteExamination 表的条件。

此外,这两个表之间没有 JOIN 的事实被您使用旧式非 ANSI 连接语法的事实所掩盖——其中表以逗号分隔,连接条件为在WHERE 子句中。我建议您使用简单的JOINs 而不使用IN 子句来解决此问题,此外,您还可以使用现代ANSI 语法:

SELECT
   N._idP,
   N.Note,
   N.Punkte,
   E.Thema
FROM
   Note AS N
   INNER JOIN Examination AS E
      ON N._idP = E._idP
   INNER JOIN Subject AS S
      On E.idF = S._idF
WHERE
   N._idS = 1
   AND S.Name = 'Physik'
;

See a Live Demo at SQL Fiddle(SQL Server 2008版本)

对于没有提供 SQLite 示例,我深表歉意——我没有安装 Web SQLite,而且 JavaScript SQLite 版本的加载速度非常非常慢。

虽然IN (subquery or correlated subquery) 语法在一方面可能更容易理解,但根据我的经验,它的使用往往会在概念上影响人,并妨碍简单的旧基本JOIN 思维。我鼓励您使用JOINs,并尽可能默认使用IN (subquery)。如果你能做到这一点,你也将能够理解IN 查询。但它似乎并没有反过来起作用。

使用 ANSI JOIN 语法的一大好处是,如果您没有 ON 子句,查询将不会运行。它还在WHEREclause 中为需要它们而不是远离的表添加了条件,此外,它在逻辑上分隔了被认为是基本JOIN 一部分的部分(这些表将总是 em> use) 以及被视为此特定查询的特殊 WHERE 过滤器的部分。

【讨论】:

  • 谢谢@DavidStarkey 我实际上是从这个开始的——我很感激。
  • 对我来说,使用 LEFT 或 RIGHT JOIN 更容易理解。您能否将其中之一添加到您的答案中(首选 LEFT JOIN)。会很好。如果我使用 INNER 或 LEFT JOIN,性能或其他方面会有所不同吗?
  • 在你的情况下:第二个使用INNER JOIN,第一个使用LEFT JOINLEFT JOIN 添加左表中不匹配右表行的所有行。请参阅manual 的最后一个要点顺便说一句:SQLite 将 , 视为连接运算符:““INNER JOIN”、“JOIN”和“,连接运算符”之间没有区别。
  • @JohannesKuhn 你是说你能做到FROM Note N, Examination E ON N._idP = E._idP?如果不是,则JOIN, 之间存在差异。即使有可能,我也不喜欢NATURAL JOIN,因为您的查询都可以通过简单地将列添加到表中来中断(如果您决定将UpdatedDate 添加到数据库中的每个表中 - 哎呀,有你所有的代码)。
  • @Cilenco 需要LEFT JOIN 的唯一原因是如果您想要一个表中的所有行,即使JOINed 表中没有匹配的行。你能解释一下你想要什么不同的结果吗?根据您的数据,在我看来INNER JOIN 是正确的,但我可能是错的。另外,您关于LEFTRIGHT 加入更容易理解的说法非常令人费解。它们并不是彼此的简单替代品,因此您永远不会根据哪个更容易理解来选择它们,而是根据您想要的效果来选择它们。对JOINs 的复习对您有帮助吗?
【解决方案2】:

试试这个:

SELECT n."_idP", n."Nota", n."Punkte", e."Thema"
FROM "Note" n, "Examination" e, "Subject" s
WHERE n."_idS" = 1
AND n."_idP" =e."_idP"
AND e."idF" = s."idF"
AND s."Name" = 'Physik'

【讨论】:

  • 使用老式的非 ANSI 连接语法不是最佳实践。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多