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

所以,根据Mehrdad对相关问题的回答 ,我知道 “正确的”数据库表列不存储列表。 相反,你应该创build另一个表,有效地保存所述列表的元素,然后直接链接到它或通过联结表。 但是,我想要创build的列表types将由唯一的项目组成(与链接问题的水果示例不同)。 此外,我的列表中的项目是明确的sorting – 这意味着如果我把这些元素存储在另一个表中,每次访问它们时都必须对它们进行sorting。 最后,这个列表基本上是primefaces的,任何时候我想访问列表,我都想访问整个列表,而不仅仅是一个列表 – 所以看起来很蠢,必须发出一个数据库查询来收集列表。

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

有没有更好的解决scheme? 如果没有更好的解决scheme,那为什么? 似乎这个问题应该不时出现。

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

谢谢大家!

约翰

更新:所以在第一个问题我得到的答案,我看到“你可以去的CSV / XML路线…但不要!”。 所以现在我正在寻找解释为什么。 指点我一些很好的参考。

此外,给你一个更好的想法,我最多:在我的数据库中,我有一个函数表,将有一个(x,y)对列表。 (这个表格还有其他的信息对于我们的讨论没有任何意义。)我永远不需要看到(x,y)对列表的一部分。 相反,我会把它们全部放在屏幕上。 我将允许用户拖动节点来偶尔更改值或添加更多的值的情节。

不,没有“更好”的方法来存储单个列中的项目序列。 关系数据库专门devise为每行/列组合存储一个值。 为了存储多个值,您必须将您的列表序列化为单个值进行存储,然后在检索时对其进行反序列化。 没有别的办法可以做你正在谈论的事情(因为你所谈论的是一个糟糕的主意,总的来说,这是不应该做的 )。

我知道你认为创build另一个表来存储这个列表是愚蠢的,但这正是关系数据库所做的。 您正在进行一场艰苦的战斗,违背了关系数据库devise最基本的原则之一,没有任何理由。 既然你声明你只是学习SQL,我强烈build议你避免这个想法,并坚持由经验丰富的SQL开发人员推荐给你的做法。

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

在过分简化事物的风险下,数据库规范化就是根据数据定义数据库的过程,以便您可以编写明智,一致的查询,并能够轻松地进行维护。 规范化旨在限制数据中的逻辑不一致和损坏,并且有很多级别。 维基百科关于数据库规范化的文章其实很不错。

基本上,规范化的第一个规则(或forms)表明你的表必须表示一个关系。 这意味着:

  • 你必须能够区分一行和其他行(换句话说,你的表必须有一些可以作为主键的东西,这也意味着没有行应该被复制。
  • 数据的任何顺序都必须由数据定义,而不是由行的物理顺序来定义(SQL基于集合的概念,这意味着您唯一应该依赖的顺序是您在查询中明确定义的顺序)
  • 每行/列交叉点必须包含一个且只有一个

最后一点显然是这里的要点。 SQL旨在为您存储您的集合,而不是为您提供一个“存储桶”,供您自己存储集合。 是的,这是可能的。 不,世界不会结束。 但是,您已经在理解SQL以及随之而来的最佳实践方面已经陷于瘫痪,立即跳入使用ORM。 LINQ to SQL非常棒,就像graphics计算器一样。 然而,同样的道理,它们不应该被用来作为知道他们所使用的过程如何工作的替代品。

你的清单现在可能完全是“primefaces”,这个项目可能不会改变。 但是,你会养成在其他项目中做类似事情的习惯,最终(很可能很快)你会碰到一个场景,你现在正适合快速简单的列表在完全不适合的地方。 在创build正确的表格时,没有太多额外的工作要做,而当你看到你的数据库devise时,你不会被其他SQL开发人员嘲笑。 此外,LINQ to SQL将会看到你的关系,并自动给你正确的面向对象的界面给你的列表。 为什么你会放弃ORM提供给你的便利,这样你就可以执行非标准和不恰当的数据库骇客?

你可以一起忘记SQL,并采用“NoSQL”方法。 RavenDB , MongoDB和CouchDB可以作为可能的解决scheme。 用NoSQL的方法,你不使用关系模型..你甚至没有限制到模式。

我所看到的很多人做的是(这可能不是最好的方法,如果我错了,纠正我):

下面给出了我在这个例子中使用的表格(这个表格包含了你给你特定女朋友的昵称,每个女朋友都有一个唯一的ID):

nicknames(id,seq_no,names) 

假设你想在一个id下存储许多昵称。 这就是为什么我们包含一个seq_no字段。

现在,把这些值填入你的表中:

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

如果你想find你的女朋友id 1的所有名字,那么你可以使用:

 select names from nicknames where id = 1; 

除了其他人所说的话之外,我还是build议你用比现在更长的时间来分析你的方法。 目前情况是项目是独一无二的。 目前情况下,诉诸这些项目将需要一个新的名单。 几乎要求名单目前很短。 尽pipe我没有具体的域名,但认为这些要求可能会发生变化,这并不算什么。 如果您序列化您的列表,那么您正在进行烘焙,而不是在更规范化的devise中不必要的。 顺便说一下,这并不一定意味着一个完整的多关系。 你可以有一个单独的子表,带有父项的外键和项目的字符列。

如果你仍然想要顺序化这个列表,那么你可能会考虑将列表存储在XML中。 一些数据库如SQL Server甚至有一个XML数据types。 我build议使用XML的唯一原因是,几乎所有的定义都需要简短。 如果列表很长,那么序列化一般是一个可怕的方法。 如果您使用CSV路线,则需要考虑包含分隔符的值,这意味着您不得不使用带引号的标识符。 由于名单很短,使用CSV或XML可能不会有太大的区别。

如果您需要在列表中查询,请将其存储在一个表中。

如果您始终需要列表,则可以将其作为分隔列表存储在列中。 即使在这种情况下,除非有非常特殊的原因,否则将其存储在查找表中。

我只是将它存储为CSV,如果它是简单的值,那么它应该是你所需要的(XML是非常详细的,序列化到/从它可能是矫枉过正,但这也是一个选项)。

这里有一个很好的答案如何拉出与LINQ的CSV。

只有一个选项没有在答案中提到。 您可以取消规范您的数据库devise。 所以你需要两张桌子 一个表包含正确的列表,每行一个项目,另一个表格包含一列中的整个列表(例如,以逗号分隔)。

这是“传统”数据库devise:

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

这里是非规范化表格:

 Lists(ListID, ListContent) 

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

如果你真的想把它存储在一个列中,并且可以查询,现在很多数据库都支持XML。 如果不查询,可以将它们存储为逗号分隔值,并在需要分离时用函数parsing出它们。 我同意所有其他人,但是如果你正在寻找使用关系数据库,规范化的很大一部分就是分离这样的数据。 我并不是说所有数据都适合关系数据库。 如果大量数据不适合模型,则可以随时查看其他types的数据库。

我想在某些情况下,你可以在数据库中创build一个FAKE“list”列表,例如商品有几张图片来显示它的细节,你可以连接所有用逗号分隔的图片的ID,并将string存入数据库,那么你只需要parsingstring,当你需要它。 我现在正在一个网站上工作,而且我打算使用这种方式。

简单的答案:如果,并且只有在确定列表总是被用作列表的情况下,那么在列表的最后加上一个字符(比如'\ 0'),这个字符不会被用在文字,并存储。 那么当你检索它时,你可以用'\ 0'来分割。 当然,还有其他方法可以解决这个问题,但这些方法依赖于您的特定数据库供应商。

作为一个例子,你可以将JSON存储在Postgres数据库中。 如果你的清单是文本,而你只是想要没有进一步麻烦清单,这是一个合理的妥协。

其他人已经提出了序列化的build议,但我并不认为序列化是一个好主意:关于数据库的一部分整洁的事情是,用不同语言编写的几个程序可以相互交谈。 如果一个Lisp程序需要加载,那么使用Java格式序列化的程序就不会做得很好。

如果你想要一个很好的方法来做这种事情,通常可以使用数组或类似的types。 例如,Postgres提供了数组作为types,并允许你存储一个文本数组,如果这是你想要的 ,并且对于使用JSON的MySql和MS SQL也有类似的技巧,而且IBM的DB2也提供一个数组types自己有用的文档)。 如果没有这个需要,这不会很常见。

通过走这条路,你所做的就是按顺序把这个列表看作是一堆东西。 至less在名义上,数据库将字段视为单个值。 但如果这就是你想要的,那么你应该去做。 这是你必须为自己做的价值判断。