我有以下表格:
基本上,我使用联结表students_courses
在学生和课程之间有很多关系
以下是填充到表格中的一些数据: 生:
课程
students_courses:
所以基本上我想为给定的学生选择full_name和c_id。因此,例如对于id = 3的学生,我将拥有Aurica 5和Aurica 6。
我的第一个方法是写:
select s.full_name,sc.c_id from students s, students_courses sc
where sc.s_id=3
但我得到了这个:
Aurica 5
Aurica 6
Aurica 5
Aurica 6
Aurica 5
Aurica 6
因此,它与students_courses表的行数重复。现在我不确定为什么会这样。
如果我是一个SQL解析器,我会像这样解析它: “从students_courses中获取c_id,从学生中获取full_name,如果students_course行尊重where过滤器,则显示它们”
使用join不是很有效,但我真的不明白为什么内连接是必要的。
select s.full_name, sc.c_id from students s
inner join students_courses sc
on sc.s_id=s.id and s.id=3;
解释一下SQL解析器解释的第一个sql是如何解释的,以及加入的原因是什么。
谢谢,
答案 0 :(得分:2)
SQL解析器不会尝试猜测两个表的关联方式。看起来数据库引擎有足够的信息通过遵循约束来解决这个问题,但SQL故意不使用FK关系来决定如何连接表;您可能希望在将来某个日期删除约束(例如为了提高性能),并且您不希望删除约束来更改连接的方式。 DBA需要自由更改索引和约束,而不必担心更改查询返回的结果。
由于它不能指望完整的信息继续下去,因此SQL引擎不会推断/猜测关系。由编写SQL的人来指定他们正在加入的内容。如果你没有给它任何指令告诉它如何连接表(使用JOIN ON子句或WHERE子句),那么它会创建一个交叉连接,它会为你提供重复的结果。
答案 1 :(得分:1)
当您从两个表中选择信息时,它所做的是所有记录的叉积,然后查找满足where子句的所有记录。学生表中有3条记录
id | full_name
---+----------
3 | Aurica
4 | Aurica
5 | Aurica
student_courses表中的6条记录。
s_is | c_id
-----+-----
3 | 5
3 | 6
4 | 7
4 | 8
5 | 9
5 | 10
因此,在where语句之前,它会创建18个不同的记录。因此很容易看出我将包含所有列。
s.id | s.full_name | sc.s_id | sc.c_id
-----+-------------+---------+--------
3 | Aurica | 3 | 5
3 | Aurica | 3 | 6
3 | Aurica | 4 | 7
3 | Aurica | 4 | 8
3 | Aurica | 5 | 9
3 | Aurica | 5 | 10
4 | Aurica | 3 | 5
4 | Aurica | 3 | 6
4 | Aurica | 4 | 7
4 | Aurica | 4 | 8
4 | Aurica | 5 | 9
4 | Aurica | 5 | 10
5 | Aurica | 3 | 5
5 | Aurica | 3 | 6
5 | Aurica | 4 | 7
5 | Aurica | 4 | 8
5 | Aurica | 5 | 9
5 | Aurica | 5 | 10
从那里它只显示cs.id = 3
的那些s.full_name | sc.c_id
------------+--------
Aurica | 5
Aurica | 6
Aurica | 5
Aurica | 6
Aurica | 5
Aurica | 6
你比较sc.s_id = s.id的第二个查询,只显示那些值相同的那些,以及c_id = 3
答案 2 :(得分:1)
首先,SQL是一种基于集合的语言,您对数据集进行操作,而不是对单个(行)数据进行操作。
如果我是一个SQL解析器,我会像这样解析它:“接受 来自students_courses的c_id,来自学生的full_name,并显示它们 如果students_course行尊重where过滤器“
在这里,你忽略了 students_courses 和学生这些集合,只是考虑了每一行数据,比如如果这些行尊重过滤器,给出我所有的信息。
JOIN
不会过滤数据(这是WHERE
所做的),而是将它们放在一起。
当您从表A中SELECT
时,您要求A中的行集,所有这些行
当您从表A SELECT
某个条件WHERE
时,您要求A中的行集尊重条件(因此SQL引擎会丢弃A中没有的行属于你描述的你的查询集。)
当你JOIN
table_a和table_b时,你要求加入a中的行集和b中的行集,获取一个新行,其行是“连接”(让我使用该术语)来自A中的行的列和来自B中的行的列;这一点,没有提供关于如何加入行的任何其他信息,只会导致table_a 加入的每一行与table_b的每一行。
这就是为什么你得不到你期望的原因。
最后,从概念的角度来看,我想指出SQL引擎不会从表或其他表中获取您请求的列,但是在(1)加入您请求的任何表中的行和(2)已过滤掉与 where 条件不匹配的任何行,它只返回您在结果集的行之后请求的列(1) )和(2)。 在现实生活中,RDBMS可能会重新排序这些操作,并根据它们可用的索引和其他查询和表格信息应用他们认为可能的任何类型的优化。
这应该可以让您大致了解正在发生的事情。但正如@GordonLinoff建议你的那样,我认为你应该在进一步发展之前获得更强大的SQL和关系数据库基础,否则它会比这更难。
作为旁注,您在FROM
子句中所拥有的是一种隐式连接,一种以前的连接语法,其中FROM
子句指定了表涉及,连接谓词的WHERE
子句(其值应与 join 数据匹配的列)。
答案 3 :(得分:0)
如果你做了类似
的事情select s.full_name,sc.c_id
from students s, students_courses sc
where sc.s_id = s.id --<-- you left this out
AND sc.s_id=3
您将获得相同的结果,此语句不需要内部联接,但使用此较新的INNER JOIN语法检索数据是一种很好的做法。
答案 4 :(得分:0)
你的两个查询实际上都是连接,只有在你的第一个例子中没有单词&#34; join&#34; (但它在那里,相信我)。
然而,这是旧式加入,不建议再使用。简而言之,它是关于NULL值的 - 这种旧式连接在解释NULL值时存在问题,这就是为什么你有错误的结果。
有关详细信息,请参阅here。