首页 文章

如何将列表存储在数据库表的列中

提问于
浏览
83

所以,根据Mehrdad's answer to a related question,我得知"proper"数据库表列没有't store a list. Rather, you should create another table that effectively holds the elements of said list and then link to it directly or through a junction table. However, the type of list I want to create will be composed of unique items (unlike the linked question'的水果示例) . 此外,列表中的项目是显式排序的 - 这意味着如果我将元素存储在另一个表中,我每次访问它时都必须对它们进行排序 . 最后,该列表基本上是原子的,因为任何时候我希望访问列表,我将要访问整个列表而不仅仅是它的一部分 - 因此,必须发出数据库查询以聚集在一起的部分似乎很愚蠢列表 .

AKX的解决方案(上面链接)是序列化列表并将其存储在二进制列中 . 但这似乎也不方便,因为这意味着我不得不担心序列化和反序列化 .

有没有更好的解决方案?如果没有更好的解决方案,为什么呢?看来这个问题应该不时出现 .

...更多信息让你知道我来自哪里 . 一旦我刚刚开始理解SQL和数据库,我就开始使用LINQ to SQL了,所以现在我有点被宠坏了因为我希望能够处理我的编程对象模型而不必考虑对象如何被查询或存储在数据库中 .

谢谢大家!

约翰

更新:所以在我得到的第一批答案中,我看到“你可以使用CSV / XML路线......但不要!” . 所以现在我正在寻找原因的解释 . 请给我一些很好的参考 .

另外,为了让您更好地了解我的目标:在我的数据库中,我有一个Function表,它将包含(x,y)对的列表 . (该表还有其他信息对我们的讨论没有影响 . )我永远不需要看到(x,y)对列表的一部分 . 相反,我将采取所有这些并在屏幕上绘制它们 . 我将允许用户拖动节点以偶尔更改值或向绘图添加更多值 .

10 回答

  • 1

    不,没有"better"方法将一系列项目存储在一列中 . 关系数据库专门设计用于存储每行/列组合的一个值 . 为了存储多个值,您必须将列表序列化为单个存储值,然后在检索时对其进行反序列化 . 没有其他方法可以做你正在谈论的一个坏主意,一般来说,永远不应该这样做 .

    我知道你认为它正在进行一场艰苦的战斗并且没有任何理由违反关系数据库设计的最基本原则之一 . 既然你说你只是在学习SQL,我会建议你避免这个想法,并坚持使用经验丰富的SQL开发人员推荐给你的做法 .

    您违反的原则称为第一范式,这是数据库规范化的第一步 .

    存在过度简化事物的风险,数据库规范化是根据数据定义数据库的过程,因此您可以针对它编写合理,一致的查询并能够轻松维护它 . 规范化旨在限制数据中的逻辑不一致和损坏,并且有很多级别 . 关于database normalization的维基百科文章实际上非常好 .

    基本上,规范化的第一个规则(或形式)表明您的表必须表示关系 . 这意味着:

    • 您必须能够区分一行与任何其他行(换句话说,您的表必须具有可用作主键的内容 . 这也意味着不应该重复行 .

    • 数据的任何排序必须由数据定义,而不是由行的物理排序定义(SQL基于集合的思想,这意味着您应该依赖的唯一排序是您在查询中明确定义的顺序)

    • Every row/column intersection must contain one and only one value

    最后一点显然是这里的重点 . SQL旨在为您存储集合,而不是为您提供"bucket"供您自己存储集合 . 是的,它结束了.1754747_t . 但是,您已经通过立即使用ORM来了解SQL以及与之相关的最佳实践 . LINQ to SQL非常棒,就像图形计算器一样 . 然而,同样地,它们不应该被用来代替它们所采用的过程实际上如何工作 .

    您的列表现在可能完全是"atomic",对于此项目可能不会更改 . 但是,你会养成做类似的习惯在其他项目中的事情,你现在已经适合你的快速简单的列表列表方法,这是完全不合适的 . 为其他SQL开发人员在查看数据库设计时嘲笑的内容创建正确的表时,没有太多额外的工作 . 此外,LINQ to SQL将会看到您的关系,并自动为您的列表提供适当的面向对象的接口 . 为什么你会放弃ORM为你提供的便利,以便你可以执行非标准和不明智的数据库hackery?

  • 0

    你可以一起忘记SQL,并采用"NoSQL"方法 . RavenDBMongoDBCouchDB跳到脑海里作为可能的解决方案 . 使用NoSQL方法,您不使用关系模型 . 您甚至不受约束模式 .

  • 3

    我见过许多人这样做(这可能不是最好的方法,如果我错了,请纠正我):

    我在下面给出了我在示例中使用的表格(该表格包含您给予特定女友的昵称 . 每个女朋友都有一个唯一的ID):

    nicknames(id,seq_no,names)
    

    假设您希望在id下存储许多昵称 . 这就是我们包含 seq_no 字段的原因 .

    现在,将这些值填充到表中:

    (1,1,'sweetheart'), (1,2,'pumpkin'), (2,1,'cutie'), (2,2,'cherry pie')
    

    如果你想找到你给你的女朋友id 1的所有名字,你可以使用:

    select names from nicknames where id = 1;
    
  • 2

    除了其他人所说的,我建议你用更长的时间分析你的方法,而不仅仅是现在 . 目前的情况是物品是独一无二的 . 目前,诉诸物品需要新的清单 . 几乎要求该列表目前很短 . 即使我没有域名细节,但认为这些要求可能会发生变化并不是一件容易的事 . 如果您对列表进行序列化,那么您将陷入一种在更规范化的设计中不必要的不灵活性 . 顺便说一句,这并不一定意味着完整的许多:许多关系 . 您可以只有一个子表,其中包含父项的外键和项的字符列 .

    如果您仍想沿着这条序列化列表的道路前进,您可以考虑将列表存储在XML中 . 某些数据库(如SQL Server)甚至具有XML数据类型 . 我建议XML的唯一原因是,几乎按照定义,这个列表需要很短 . 如果列表很长,那么通常序列化它是一种糟糕的方法 . 如果您使用CSV路线,则需要考虑包含分隔符的值,这意味着您必须使用带引号的标识符 . 假设列表很短,无论您使用CSV还是XML,都可能没什么区别 .

  • 0

    如果需要在列表中查询,请将其存储在表中 .

    如果您总是想要列表,则可以将其存储为列中的分隔列表 . 即使在这种情况下,除非您有非特定原因,否则将其存储在查找表中 .

  • 10

    我只是将它存储为CSV,如果它是简单的值,那么它应该是您所需要的全部(XML非常详细,并且序列化到/从它可能是过度的,但这也是一个选项) .

    这是一个good answer,用于如何使用LINQ提取CSV .

  • 7

    答案中只提到了一个选项 . 您可以对数据库设计进行去规范化 . 所以你需要两张 table . 一个表包含正确的列表,每行一个项目,另一个表包含一列中的整个列表(例如,以逗号分隔) .

    这里是'传统'数据库设计:

    List(ListID, ListName) 
    Item(ItemID,ItemName) 
    List_Item(ListID, ItemID, SortOrder)
    

    这里是非规范化表:

    Lists(ListID, ListContent)
    

    这里的想法 - 您使用触发器或应用程序代码维护Lists表 . 每次修改List_Item内容时,列表中的相应行都会自动更新 . 如果您主要阅读列表,它可以很好地工作 . 优点 - 您可以在一个声明中阅读列表 . 缺点 - 更新需要更多时间和精力 .

  • 0

    如果你真的想将它存储在一个列中并让它可查询,那么很多数据库现在都支持XML . 如果不查询,则可以将它们存储为逗号分隔值,并在需要将它们分开时使用函数解析它们 . 我同意其他所有人,但如果你想使用关系数据库,规范化的一个重要部分就是分离这样的数据 . 我并不是说所有数据都适合关系数据库 . 如果您的大量数据不适合模型,您可以随时查看其他类型的数据库 .

  • 1

    我认为在某些情况下,您可以在数据库中为项目创建一个FAKE“列表”例如,商品有一些图片来显示其详细信息,您可以连接用逗号分割的图片的所有ID并将字符串存储到数据库中,然后您只需要在需要时解析字符串 . 我现在在网站上工作,我打算用这种方式 .

  • 134

    简单的答案:当且仅当您确定该列表将始终用作列表时,然后将该列表一起加入到一个字符(例如'\ 0')的末尾,该字符将不会用于文本永远,并存储 . 然后当你检索它时,你可以用'\ 0'分割 . 当然还有其他方法来处理这些问题,但这些方法取决于您的特定数据库供应商 .

    例如,您可以将JSON存储在Postgres数据库中 . 如果您的列表是文本,并且您只是想要列表而没有进一步的麻烦,这是一个合理的妥协 .

    其他人已经提出了序列化的建议,但我并不认为序列化是一个好主意:关于数据库的一些巧妙之处在于,用不同语言编写的几个程序可以相互通信 . 如果Lisp程序想要加载它,那么使用Java格式序列化的程序将无法做到这一点 .

    如果你想要一个很好的方法来做这种事情,通常有阵列或类似的类型可用 . Postgres for instance, offers array as a type, and lets you store an array of text, if that's what you want,使用JSON的MySqlMS SQL也有类似的技巧,IBM's DB2也提供了数组类型(在他们自己的有用文档中) . 如果没有必要,这就不会那么常见了 .

    走这条路你失去的是列表中的概念,它是一堆顺序的东西 . 至少在名义上,数据库将字段视为单个值 . 但如果这就是你想要的,那么你应该去做 . 这是你必须为自己做出的 Value 判断 .

相关问题