奇怪的是很多很多和一对多的关系

时间:2008-10-23 06:16:00

标签: sql constraints

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

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

客户添加了以下要求:

从表B​​内部加入A和C获取信息,并在同一查询中将A和C关联成一对多的关系

类似的东西:

alt text http://img247.imageshack.us/img247/7371/74492374sa4.png

我尝试过查询,但总是得到0行。客户坚持认为我可以完成要求,但我对此表示怀疑。有什么意见吗?

PS。我没有更具描述性的标题,任何想法?

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

更新: 有一个联系人表,一个包含每个联系人信息的表和关系表。要获取联系人的信息,我必须与信息保持1:1的关系,并且每个联系人都可以拥有喜欢和地址簿;这就是实现许多关系的原因。

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

6 个答案:

答案 0 :(得分: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中的id_class条目不同(例如,如果s.id_class指的是仅出现在该表中的homeroom类赋值,而many_to_many.id_class指的是用于信用的类并且不包括homeroom类),你最好把c分成两个表。

如果情况并非如此,我很难理解你为什么要把一个班级硬连线到桌子上。

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

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

答案 1 :(得分:3)

也许这是缺乏咖啡因,但我无法想到想要这样做的正当理由。在你给出的例子中,你有学生,班级和一张与两者相关的表格。如果你想用查询来做什么,用简单的英语,肯定它必须由student表或class表驱动。即

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

你能更好地解释这个要求吗?如果没有,请告诉您的客户将其吸收。在学生和班级之间直接建立关系(A和C),看起来像是纯粹的疯狂,你已经有了表B这样做......

答案 2 :(得分:3)

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

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

答案 3 :(得分: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);

答案 4 :(得分: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

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

答案 5 :(得分:0)

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

  

从表中获取信息   B内部连接A和C,并在   相同的查询涉及a中的A和C.   一对多的关系

看起来这就是您将需求转化为的内容。 您能用简单的英语指定要求,因为您的客户希望得到什么结果?