在SQL中选择多个M:N关系的最佳方法是什么?

时间:2009-01-25 03:32:08

标签: sql join

我开始了一个鼓励我扩展SQL知识的项目。我已经学到了很多东西,但我已经达到了可以看到问题的程度,但我不知道如何正确研究解决方案。我已经点击了SO,谷歌和MySQL文档,但要么我提出了错误的问题,要么我不知道如何提出正确的问题。我的数据由三个主表构成,其中一个表与其他两个表有M:N关系。我将这些关系存储在另一对表中,因为我认为这是“最佳方式”:

books (book_id INT PRIMARY KEY, book_title VARCHAR)
authors (author_id INT PRIMARY KEY, author_name VARCHAR)
subjects (subject_id INT PRIMARY KEY, subject_name VARCHAR)
book_authors (book_id INT, author_id INT)
book_subjects (book_id INT, subject_id INT)

(前三个表实际上有两列以上,但它们不相关。)

修改

显然,我很想问清楚的问题,但后来我已经知道了。 : - )

我正在尝试解决的问题是如何最有效/高效地将数据从数据库导入我的应用程序。一旦我拥有它,我可以重新安排它,但我需要,我相信我可以做到这一点,无论数据是如何“塑造”出来的数据库。使用五个单独的SELECT * FROM …语句可能是微不足道的,使用我之前发布的交叉产品“frankenjoin”也是微不足道的。但是,我对SQL有足够的了解,发现前者剥夺了数据库引擎的工作机会。我对SQL有足够的了解,以确定后者是否同样糟糕。

那么怎么样:而不是问解决方案提出了什么问题,而你的解决方案是什么?如果您有这样的数据,那么如何从数据库中选择它? (还有什么原因?)你甚至可能以不同的方式安排表格吗?

6 个答案:

答案 0 :(得分:3)

我认为您可能希望将其作为两个查询,一个用于作者,一个用于主题,但是如果您愿意,可以使用UNION将它们组合成一个结果。

SELECT books.book_id, books.book_title, 
      'author' as record_type, authors.author_name as record_value
LEFT JOIN book_authors ON books.book_id = book_authors.book_id
LEFT JOIN authors ON authors.item_id = book_authors.author_id
UNION
SELECT books.book_id, books.book_title,
       'subject' as record_type, subjects.subject_name as record_value
LEFT JOIN book_subjects ON books.book_id = book_subjects.book_id
LEFT JOIN subjects ON subjects.subject_id = book_subjects.subject_id;

我不确定除了往返数据库之外,它还能保存任何其他内容。我提供它只是为了对你的知识做出的潜在贡献,而不是希望它对你的直接问题有所帮助。

答案 1 :(得分:2)

您认为应该回来的是什么?您不能在查询中返回一个元组内的列表,因此您当前的结果似乎是在一个查询中获取所有数据的唯一方法。

更新:SQL不支持层次结构,因此您必须自己构建(假设您没有使用可以为您执行此操作的ORM工具)。一种方法是前往数据库以获取所有书籍,然后为每本书为该书的作者进行一次旅行,为该书的主题进行一次旅行。不过,这可能是数据库的大量旅行。另一种方法是将所有数据(如您的问题中)带回来,然后构建一个层次结构。哪一个更好取决于很多因素。即使客户端代码可能更复杂,也可能会选择一个数据库行程解决方案;一般规则是到数据库的往返是昂贵的,所以我倾向于解决方案,不会随着结果的数量线性增加这种旅行的次数。

答案 2 :(得分:1)

创建一个巨大的多连接表,并在您的应用程序中重构,从而破坏了首先使用数据库的目的。你的表中有一切很好的规范化,你为什么要把所有的努力都扔掉?

我要做的是建立并维护与数据库的连接。当您需要某些数据时,创建一个select语句,该语句仅连接您需要的表,并仅为您提供当时所需的数据,将其发送到数据库,并使用结果。如果其他人在您查询时插入并更新数据库中的行,则结果将是最新的。

如果您需要Emily Dickinson的所有书籍,请加入您的书籍和作者表。如果您需要所有撰写关于糕点制作书籍的作者,请加入作者和主题表。

答案 3 :(得分:0)

你得到的正是你所描述的,任何标准的主流开发者都会以同样的方式完成同样的事情。但显然它与你的形状和大小的心理预期不符。

首先阅读3本书,不同数量的作者和科目,然后列出你想看到的内容。然后我们可以讨论如何到达那里。

我认为你不会找到能让你到达那里的方格。可能你想要更像树结构的东西?

+ Title 1
+----+ Authors
     + ---- Author 1
     + ---- Author 2
+    + Topics
     + ---- Topic A
etc.

我发现沿着这些线的任何东西最容易使用另一个抽象层中的映射工具来导出;虽然有一些方法可以扭转关系数据,如果你有技能(例如分析立方体和查询,返回依赖的辅助查询等),它们通常涉及专有扩展(例如LINQ);但你可能不想去更复杂(阅读:复杂)的东西,直到你完全掌握了这样的东西。

答案 4 :(得分:0)

我通常认为以这种方式恢复数据并不是很有用。我可以相互关联的多个结果集往往更有用。您也不会以这种方式在结果集中包含无关数据(每行返回8行,并且书的列数相同)。

答案 5 :(得分:-1)

您可以使用MS SQL Server返回多个结果集。 SELECT * FROM books; SELECT * FROM book_authors; SELECT * FROM authors; SELECT * FROM book_subjects; SELECT * FROM subject;

然后使用该信息加载带有关系的.NET DataSet,或创建实体对象,如果不使用.NET或DataSet,则封装关系。

如果您使用的是.NET 3.5,那么请查看LINQ to SQL或LINQ to Entities,以简化创建所需代码的工作。

相关问题