3

快速前言:我使用 SQL 实现持久化(Haskell) 和esqueleto

无论如何,我想要一个带有 type 列的 SQL 表[String],即字符串列表。现在我想进行一个查询,它为我提供所有记录,其中给定列表是记录中的一个子列表。

例如表与

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

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

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

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

谢谢。

4

2 回答 2

3

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

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

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

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

一种更强大的方法是将您的存储任务重新定义为可以轻松融入关系数据库概念的内容。即尝试将其放在关系方面。实体和关系很简单,因此可以避免极端情况。您无需担心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])]

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

对于给定的 List ,如上所述的集合逻辑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 -- ... ?

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

于 2015-09-08T15:55:13.480 回答
1

通过使用[String],persistent 将整个列表转换为带引号的字符串,这使得在 SQL 中使用起来非常困难。

您可以执行以下操作:

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

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

更好的方法是:

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

  2. 将数据建模为:

    对象:

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

    对象类别:

    ObjectID  Category
    0   math
    0   algebra
    1   personal
    1   life
    2   algebra
    2   university
    2   personal
    
于 2015-09-08T14:37:47.820 回答