SQL:List-Field 包含子列表

Posted

技术标签:

【中文标题】SQL:List-Field 包含子列表【英文标题】:SQL: List-Field contains sublist 【发布时间】:2015-09-08 12:36:56 【问题描述】:

快速前言:我使用 SQL 实现 persistent (Haskell) 和 esqueleto。

无论如何,我想要一个包含[String] 类型列的 SQL 表,即字符串列表。现在我想做一个查询,它给我所有的记录,其中给定列表是记录中的一个子列表。

例如表

ID  Category
0   ["math", "algebra"]
1   ["personal", "life"]
2   ["algebra", "university", "personal"]

查询["personal", "algebra"] 将只返回 ID=2 的记录,因为["personal", "algebra"]["algebra", "university", "personal"] 的子列表。

对于我广受欢迎的子列表和“基本”SQL 运算符的可变长度,这样的查询是否可行?

如果有人知道他们在持久性/esqueleto 方面的方式,那当然很棒。

谢谢。

【问题讨论】:

对SQL使用合适的数据结构,它是一个联结表,而不是一个包含列表的字符串。 【参考方案1】:

扩展 Gordon Linoff 的评论和之前的答案:

SQL 数据库的功能有时会受到限制。由于[String] 中字符串的顺序似乎无关紧要,因此您正尝试将set 之类的内容放入关系数据库中,并且对于您的查询,您建议使用is a subset of 运算符之类的内容。

如果有一个提供这些结构的数据库引擎,那么使用它就没有错(我不知道)。但是,逼近您设置的逻辑(或数据库本身不支持的任何逻辑)有缺点:

您必须明确处理边缘情况(参见 xnyhps 的回答) 您需要在代码中明确处理它,而不是隐藏存储数据的复杂性 您需要研究数据库引擎,而不是编写 Haskell 代码 数据库和 Haskell 代码之间的接口变得模糊

一种更强大的方法是将您的存储任务重新定义为可以轻松融入关系数据库概念的内容。 IE。试着把它放在关系的角度。 实体和关系很简单,因此可以避免极端情况。您无需担心 db 后端究竟如何存储您的数据。您根本不必为数据库操心。并且您的界面被简化为相当简单的查询(使用连接)。所有不能(相对)容易通过查询实现的东西,都(可能)属于 Haskell 代码。

当然,具体情况根据具体情况而有所不同。

在你的具体情况下,你可以使用这样的东西:

Table: Category
ID Description
0  math
1  algebra
2  personal
3  life
4  university

Table: CategoryGroup
ID  CategoryID
0   0
0   1
1   2
1   3
2   1
2   4
2   2

...其中外键关系允许具有类别组。在这里,您正在使用它擅长的关系数据库。为了查询CategoryGroup,您需要连接这两个表,结果是类型

[(Entity CategoryGroup, Entity Category)]

我会在 Haskell 中将其转换为类似的东西

[(Entity CategoryGroup, [Entity Category])]

为每个CategoryGroup 收集Category 实体的位置(这需要deriving (Eq, Ord) 在您的CategoryGroup-Model 中)。

如上所述,对于给定列表cs :: [Entity Category],设置逻辑将如下所示

import qualified Data.Set as Set
import Data.Set (isSubsetOf)
let s = Set.fromList ["personal", "algebra"]
let s0 = Set.fromList $ map (categoryDescription . entityVal) cs
if s `isSubsetOf` s0 -- ... ?

刚开始习惯关系数据库的限制可能会很烦人。我想,对于最重要的事情(持久化数据)来说,一个健壮的概念通常比一个强大的概念更好,而且总是知道你的数据库在做什么是值得的。准确

【讨论】:

非常感谢您的详尽回答!我将按照您的建议重组我的数据库!【参考方案2】:

通过使用[String],persistent 将整个列表转换为带引号的字符串,因此很难从 SQL 中使用。

你可以这样做:

mapM (\cat ->
         where_ (x ^. Category `like` (%) ++. val (show cat) ++. (%)))
     ["personal", "algebra"]

但这很脆弱(当类别包含"等时可能会中断)。

更好的方法是:

    如果数据库足够小,您可以在 Haskell 中进行过滤。

    将数据建模为:

    对象:

    ID  ... 
    0   ...
    1   ...
    2   ...
    

    对象类别:

    ObjectID  Category
    0   math
    0   algebra
    1   personal
    1   life
    2   algebra
    2   university
    2   personal
    

【讨论】:

以上是关于SQL:List-Field 包含子列表的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server int 转换忽略子查询?

sql 包含于语法

从包含不同长度子列表的列表中构造所有组合

如何测试一个列表是不是包含另一个列表作为连续子序列?

如何在标准 SQL 的 WHERE 子句中使用 WITH 子查询作为选项列表

如何返回仅包含某些数量的原始列表的列表的子列表[重复]