3

我知道我会投反对票,但我必须确定这是否合乎逻辑。

我有三个表A,B,C。B是用于在A和C之间建立多对多关系的表。但问题是A和C也直接以一对多关系相关

一位客户添加了以下要求:

从表B中获取信息,内联A和C,并在同一个查询中以一对多关系关联A和C

就像是:

替代文字 http://img247.imageshack.us/img247/7371/74492374sa4.png

我尝试进行查询,但总是返回 0 行。客户坚持我能完成要求,但我对此表示怀疑。任何意见?

PS。我没有更具描述性的标题,有什么想法吗?

更新:感谢 rcar,在某些情况下,这可能是合乎逻辑的,以便了解学生上过的所有课程的历史记录(假设学生一次只能上一门课)

更新:有一个联系人表,一个包含每个联系人信息的表和关系表。要获取联系人的信息,我必须与 Information 建立 1:1 的关系,并且每个联系人都可以拥有喜欢和通讯录;这就是实现多对多关系的原因。

完整的想法是获取联系人的姓名和他的通讯录。现在我得到了客户的想法......我在查询时遇到了问题,基本上我正在尝试使用 jdecuyper 编写的查询,但正如他警告的那样,我没有得到任何数据

4

6 回答 6

5

这是一个可行的方案。你可以在一个查询中加入一个表两次,通常给它分配一个不同的别名以保持事情的正确性。

例如:

SELECT s.name AS "student name", c1.className AS "student class", c2.className as "class list"
FROM s
JOIN many_to_many mtm ON s.id_student = mtm.id_student
JOIN c c1 ON s.id_class = c1.id_class
JOIN c c2 ON mtm.id_class = c2.id_class

这将为您提供所有学生姓名和“硬编码”课程的列表,其中包含来自 many_to_many 表的所有课程。

也就是说,这个模式没有逻辑意义。据我所知,您希望学生能够拥有多个班级,因此 many_to_many 表应该是您希望找到与学生关联的班级的地方。如果表 s 中使用的 id_class 条目与 many_to_many 中的条目不同(例如,如果 s.id_class 指的是仅出现在该表中的 homeroom 类分配,而 many_to_many.id_class 指的是信用类并且不包括 homeroom 类),您最好将 c 拆分为两个表。

如果不是这种情况,我很难理解为什么你想要一个类硬连线到 s 表。

编辑:刚刚看到你的评论,这是一个虚构的模式来举个例子。在其他情况下,这可能是一种明智的做事方式。例如,如果您想跟踪公司位置,您可能有一个 Company 表、一个 Locations 表和一个 Country 表。Company 表可能有一个指向国家/地区的一对多链接,您可以在其中跟踪公司总部所在的国家/地区,但通过 Locations 的多对多链接可以跟踪公司拥有商店的每个地方。

如果您可以提供有关架构对您的客户真正代表什么的真实信息,那么我们可能更容易确定在这种情况下它是否合乎逻辑。

于 2008-10-23T06:39:31.977 回答
3

也许是因为缺乏咖啡因,但我想不出想要这样做的正当理由。在您给出的示例中,您有学生、班级和一个将两者联系起来的表格。如果您考虑一下您希望查询做什么,用简单的英语,肯定它必须由student表或class表驱动。IE

  • 选择学生 1245235 参加的所有课程
  • 选择所有上 101 班的学生

你能更好地解释需求吗?如果没有,请告诉您的客户接受它。直接在学生和班级之间建立关系(A 和 C),这似乎是纯粹的疯狂,你已经有表 B 可以做到这一点......

于 2008-10-23T06:40:38.200 回答
3

请记住,可以通过多对多来表示一对多关系,最简单的方法是在其中添加一个字段来指示关系的类型。然后你可以有一个“当前”记录和任意数量的“历史”记录。

顺便说一句,客户的“要求”是给定的吗?如果是这样,我想我会重新定义我与他们的关系:他们应该告诉我他们想要的“什么”(理想情况下,在商业领域的语言中,他们的问题是什么)并将“如何”留给我。如果他们确切地知道应该如何实现这个东西,那么我倾向于在编辑器中打开源代码并将它们留给它!

于 2008-10-23T10:07:40.560 回答
2

我假设 s.id_class 表示学生当前的班级,而不是她过去上过的班级。

rcar 显示的解决方案有效,但它在每一行上重复 c1.className。

这是一种不重复信息的替代方法,它使用更少的连接。您可以使用表达式将 s.id_class 与通过 mtm 表匹配的当前 c.id_class 进行比较。

SELECT s.name, c.className, (s.id_class = c.id_class) AS is_current
FROM s JOIN many_to_many AS mtm ON (s.id_student = mtm.id_student)
  JOIN c ON (c.id_class = mtm.id_class);

所以 is_current 将在一行上为 1(真),在所有其他行上为 0(假)。或者,您可以使用CASE构造输出更多信息:

SELECT s.name, c.className, 
  CASE WHEN s.id_class = c.id_class THEN 'current' ELSE 'past' END AS is_current
FROM s JOIN many_to_many AS mtm ON (s.id_student = mtm.id_student)
  JOIN c ON (c.id_class = mtm.id_class);
于 2008-10-23T19:20:36.277 回答
1

这似乎没有意义。像这样的查询:

SELECT * FROM relAC RAC
  INNER JOIN tableA A ON A.id_class = RAC.id_class 
  INNER JOIN tableC C ON C.id_class = RAC.id_class 
    WHERE A.id_class = B.id_class

可以生成一组数据但不一致。或者,我们可能遗漏了有关这 3 个表的内容和关系的一些重要信息。

于 2008-10-23T06:37:41.530 回答
0

我个人从未听过客户的要求听起来像:

从表B中获取信息,内联A和C,并在同一个查询中以一对多关系关联A和C

看起来这就是您将需求翻译成的内容。您能否用简单的英语指定要求,作为您的客户想要得到的结果?

于 2008-10-23T10:28:25.150 回答