【问题标题】:Sql design problem - items in multiple sectionsSql设计问题-多个部分中的项目
【发布时间】:2010-09-13 20:14:10
【问题描述】:

我有一个sections 表和一个items 表。

问题是每个项目可能在一个或多个部分中,因此每个项目的简单“section_id”将不起作用,并且 sql 没有办法存储数组,我可以说“WHERE 5 in section_ids"...

我考虑过将 id 列表存储为逗号分隔的字符串,问题是我看不到任何方法来检查项目是否在 sql 查询的给定部分中。我在这里看到的唯一选项是选择整个表,并在 php.ini 中解析字符串。不用说,这不是一个好主意。

有没有更好的方法来“链接”具有多个部分的项目,并且能够轻松选择给定部分 ID 的所有项目?

【问题讨论】:

  • 如果您使用 MySQL 并且您的数据集很大或者每个项目的节数很小,那么 FIND_IN_SET 选项实际上可能值得研究。如果以上都不适用,那么请继续使用多对多选项,这至少具有正统的优点。

标签: sql database-design


【解决方案1】:

您需要一个中间查找表:

CREATE TABLE item_in_section (item_id int, section_id int)

(我猜你的密钥类型,使用合适的)。

在一个部分中查找项目:

SELECT item.* from item, item_in_section WHERE item_in_section.item_id = item.item_id AND item_in_section.section_id = X GROUP BY item_id

查找项目所属的部分

SELECT section.* from section, item_in_section WHERE item_in_section.section_id = section.section_id AND item_in_section.item_id = Y GROUP BY section_id

【讨论】:

    【解决方案2】:

    为了表示多对多关系,您需要一个带有 SectionId 和 ItemId 的支持表。两者都应该是各自表的外键,并且该表的主键应该是两列。

    来自Wikipedia

    由于大多数 DBMS 仅支持一对多关系,因此有必要通过第三个联结表物理实现此类关系,例如 AB 具有两个一对多关系 A -> AB 和 B -> AB。在这种情况下,AB 的逻辑主键由两个外键(即 A 和 B 的主键的副本)组成。

    【讨论】:

      【解决方案3】:

      您需要第三个表,称为联结表,它提供 N 到 N 关系以及指向父表的 2 个外键。

      【讨论】:

        【解决方案4】:

        您需要第三个表 itemsPerSection,其主键由 itemid 和 sectionid 组成,这样您就可以建立 N 对 N 关系并且非常容易搜索。

        所以:

        Items   -   ItemsPerSection   -   Secion
        itemid  <->   itemid
                     sectionid        <->   sectionid
        

        【讨论】:

          【解决方案5】:

          我知道的方式(但我不是一个经验丰富的数据库设计者!),我在几个数据库中看到,是有第三个表:它有两列,一列是 section 表的 ID,一列是items 表的 ID。
          它无需太多成本就可以在这些条目之间创建关系,如果您从两个 ID 中创建复合索引,则可以进行快速搜索。

          【讨论】:

            【解决方案6】:

            您说的是多对多关系。采用规范化形式,最好使用第三个表处理:

            items
            sections
            itemsections
            

            itemsections 中的每一行都有一个 item id 和一个 section id。对于正常的一对多关系,这不是必需的,但这是您所查看内容的标准做法。

            【讨论】:

              【解决方案7】:

              您需要将部分关系存储在第二个表中。这是一个非常简单的例子:

              CREATE TABLE foos (
                  id              INTEGER,
                  name            VARCHAR
              )
              
              CREATE TABLE foo_sections (
                  foo_id              INTEGER,
                  section_name        VARCHAR,
              )
              
              -- Add some 'foos'
              INSERT INTO foos (1, 'Something');
              INSERT INTO foos (2, 'Something Else');
              
              -- Add some sections for each 'foo'
              INSERT INTO foo_sections (1, 'Section One');
              INSERT INTO foo_sections (1, 'Section Two');
              INSERT INTO foo_sections (2, 'Section One');
              
              -- To get all the section names for a specific 'foo' record:
              SELECT section_name FROM foo_sections WHERE foo_id = 1
              > Section One
              > Section Two
              

              当然,您可以在第二个表中存储对第三个“sections”表的引用,但为了清楚起见,我将其排除在外。

              祝你好运:)

              【讨论】:

                【解决方案8】:

                您需要在两者之间放置一个交集表,即描述哪些项目在哪些部分中的表。

                有点像..

                CREATE TABLE item_sections (
                  ID datatype
                  ITEM_ID datatype,
                  SECTION_ID datatype);
                

                然后您需要连接表以获取数据...

                SELECT items.*
                FROM   items, item_sections
                WHERE  items.id = item_sections.item_id
                and    item_sections.section_id = the-id-of the-section-you-want
                

                【讨论】:

                  【解决方案9】:

                  您可以在一个字段中存储多个 ID,用逗号分隔,然后使用 FIND_IN_SET 命令:

                  SELECT * FROM items WHERE FIND_IN_SET(5, section_id);
                  

                  http://dev.mysql.com/doc/refman/5.0/en/string-functions.html#function_find-in-set

                  【讨论】:

                  • 不知道为什么这被如此粗暴地否决了。它仅适用于 AFAICS,在 MySQL 中,但鉴于此,它似乎是一个有效的答案。而且由于 MySQL 对于单表/单索引查询的速度非常快,因此值得一试。至少让我投赞成票...
                  • 函数使用通常会阻止索引使用。如果是这种情况,那么投反对票是理所当然的。
                  猜你喜欢
                  • 1970-01-01
                  • 2020-10-12
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2022-07-13
                  • 2011-03-18
                  相关资源
                  最近更新 更多