【问题标题】:How do I best store a list of numbers in a relational database?如何最好地将数字列表存储在关系数据库中?
【发布时间】:2009-09-11 03:42:28
【问题描述】:

我想将数字列表(本质上是数学术语中的set)存储在关系数据库中,特别是 SQL Server 2005。

理想情况下,我希望它是给定表格上的单列,但我愿意听取任何解决方案。正如我所说,我需要存储的数据是一组数字。

  • 不需要是连续的(即间隙是可以的、正常的和典型的)
  • 范围是可能的(即 1 - 4),但虽然我想以这种方式显示它,但我可以使用快捷方式来存储它
  • 也可以是“全部”,因此对于这种“无限”情况,必须至少保留一个值,最好是逻辑上的保留
  • 数字列表不必按顺序排列(即 3、2、9、5),但最好且完全合理的是,在插入之前对它们进行排序,因为只有代码会进行插入,而不是手动用户。不过,它可能不应该依赖或期望列表已经排序。
  • 数字集应该可以轻松搜索到子集(见下文)
  • 所有数字都应该是不同的(不得重复),但这可以并且将在插入之前强制执行

此列旨在存储该行适用的给定流程的所有“步骤编号”。因此,每一行可以以任何顺序、范围或顺序应用于一个或多个步骤。可能的最大步数(基本上是最大范围)因行而异,尽管我非常怀疑它们中的任何一个都会达到数百个,因此在 99.9% 的情况下,最大值不应超过 20 或 30,而且我如果它接近 100 会感到惊讶。保证每一行至少有一个值(步骤)(即,有一行不适用于任何步骤是没有意义的),但我图这就像将列设置为not null 一样简单。

无论它是如何存储的,我都希望它易于搜索。例如,我宁愿不必费力地编写 SQL 查询来查找所有适用于“步骤 3”的行。如果给定的行有多个适用的步骤(例如 2、3、7 和 8),则在按步骤 3 搜索时匹配它应该不会太难。

另外,虽然我希望它在查看原始数据时具有某种逻辑意义(适用于在我不在场后需要在系统上工作的任何人,因此他们不必阅读厚厚的文档来找出我晦涩的编码),我愿意在这方面做出妥协。因此,将列表编码为可以可靠解码的内容是可以接受的。

如果这是一个骗局,我深表歉意 — 我一直在谷歌搜索,但我怀疑我的这个问题是因为不知道要搜索什么或如何表达或调用它来找到我正在寻找的东西。

在更多的评论说明中,我想知道这是否不是关系数据库不足的领域之一。不幸的是,我在这里别无选择。我必须将它存储在 SQL Server 中。恐怕单独保存到文件或其他一些持久性数据存储是不可能的。

【问题讨论】:

    标签: database-design types


    【解决方案1】:

    我不记得正确的术语,但正确的方法是创建如下表:

    |  id  |  table1_id  |  value  |
    --------------------------------
    |   0  |          1  |      1  |
    |   1  |          1  |      2  |
    |   2  |          1  |      3  |
    |   3  |          1  |      7  |
    |   4  |          1  |      9  |
    |   5  |          2  |      1  |
    |   6  |          2  |      3  |
    | ...  |        ...  |    ...  |
    

    对于 table1 中的每个值,您将所需的值添加到此表中。

    对于“全部”,您可以在 table1 中创建一个列,如果您想要全部,您可以设置一个标志。 (我在 MySql 中使用 'enum' 但我不确定 SQL Server 中是否存在)。

    我不确定是否有一些特定于 Sql Server 的方式来执行此操作,因为我主要使用 MySql。

    【讨论】:

    • 我提到了平台,但老实说,我希望答案对于任何功能合理的关系数据库系统来说都足够通用。我宁愿不依赖微软绑定的解决方案,但如果有一些漂亮的技巧,我完全赞成。例如,我经常使用公用表表达式,我很确定它们是 SQL Server 特有的功能。
    【解决方案2】:

    为什么额外的表步骤(processID JOIN,step INT)不是一个选项? 我很确定这将是最容易维护/编码的。

    SELECT process.name FROM process, steps WHERE process.id = steps.processID AND steps.step = 3;
    

    请原谅我的 SQL,但已经有一段时间了 :)

    编辑:UNIQUE(processID, step) 是可取的。

    【讨论】:

      【解决方案3】:

      我会使用简单而规范的关系设计:CREATE TABLE 范围(process_id int、num_low int、num_hi int)。后两列指定范围。每列的独立索引。对于“特殊”无穷大值,只需使用 maxints 或额外的布尔列。

      优点:轻松搜索特定数字是否在范围内,或者范围是否相交。易于维护。一般的可理解性和简单性。

      缺点:修改集合时需要一些逻辑,即检查新插入或修改的范围是否相交。可能需要拼接范围。

      【讨论】:

      • 但是列表不需要(通常也不需要)一个很好的简单范围。通常它是一个或两个,可能是三个不同的数字,没有特定的顺序(即 3、5、9)。只是偶尔是 1 - 4。
      【解决方案4】:

      下面做一个子表(MitMaro)的答案是“标准”方式。

      如果您必须将一组数字放入一个列或一个表中,但我能想象的唯一方法是使用按位运算来存储该集合,并且您可以在数据查询中使用按位运算来查找正在设置的特定位.快速谷歌搜索表明 MSSql 2005 支持这一点,但最多只能支持 32 位 int,所以如果你通过 32 步就会遇到问题。

      总而言之,子表是最标准的,它可以对表进行一些更易于理解的查询。这也是支持任何未来需要大于 32 个值映射的情况的最安全方法。

      【讨论】:

        【解决方案5】:

        如果您没有绑定到 SQL Server,Postgresql 通过array 对这种事情提供了很好的支持。它们甚至对无穷大有特殊的价值。

        如果你绑定到 SQL Server,MitMaro 的方式是最好的。

        【讨论】:

        • 有趣的是它有这个。我想要类似“数组”数据类型的东西。但是,是的,我需要使用我们所拥有的 --- SQL Server。 :)
        【解决方案6】:
        create table setmember (setid int, setmemberid int)
        create unique nonclustered index idx_setmember_idx1 on setmember (setid, setmemberid)
        

        让我假设“全部”有一个幻数(-1 或 999999999)。

        这对于基于每个集合的查询和通过非聚集索引的更新插入都将是高性能的。唯一性强制不重复条目。强制执行“全部”或多个集合成员作为约束是有问题的,但尽管可以在触发器中完成,但收益会递减。

        额外添加

        create nonclustered index idx_setmember_idx2 on setmember (setmemberid, setid)
        

        允许高效的反向查找查询。

        如果使用数组类型,可能无法实现高效的反向查找。

        请注意,以上所有 SQL 均符合 ANSI。

        【讨论】:

          【解决方案7】:

          最终使用solution to a similar question

          不过还是谢谢!我喜欢阅读大家对数据库设计这些深奥领域的意见。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-08-15
            • 1970-01-01
            • 2021-03-15
            • 1970-01-01
            • 2010-09-26
            • 1970-01-01
            • 1970-01-01
            • 2016-11-26
            相关资源
            最近更新 更多