【问题标题】:How to do a "SELECT ... IN (SELECT ...)" using Esqueleto?如何使用 Esqueleto 执行“SELECT ... IN (SELECT ...)”?
【发布时间】:2017-05-28 19:35:27
【问题描述】:

考虑以下两个模型和一个GET /articles/:slug/comments请求,我想根据它的slug检索属于一篇文章的cmets。

Article json sql=articles
    slug        Slug
    title       Text
    description Text
    body        Text
    createdAt   UTCTime default=now()
    updatedAt   UTCTime Maybe default=NULL
    userId      UserId
    UniqueSlug  slug

Comment json sql=comments
    body      Text
    createdAt UTCTime default=now()
    updatedAt UTCTime Maybe default=NULL
    articleId ArticleId
    userId    UserId

使用持久化的rawSql,我们可以如下实现

getCommentsForArticle :: Slug -> App (Cmts [Entity Comment])
getCommentsForArticle slug = do
    comments <- runDb $ rawSql stm [toPersistValue slug]
    return (Cmts comments)
        where stm = "SELECT ?? FROM comments \
                    \WHERE article_id IN (\
                        \SELECT id FROM articles WHERE slug = ?)"

但是,鉴于我想维护 Haskell 和 SQL 之间的类型安全,我想使用 esqueleto 重写它。这是我正在努力的部分。通过阅读文档,sub_select 似乎是完成这项工作的工具。这是我所拥有的:

getCommentsForArticle :: Slug -> App (Cmts [Comment])
getCommentsForArticle slug = do
    comments <- E.select $
        E.from $ \cmts -> do
            let subQuery =
                    E.from $ \arts -> do
                        E.where_ $ arts ^. ArticleSlug ==. E.val slug
                        return (arts ^. ArticleId)
            E.where_ $ cmts ^. CommentArticleId ==. E.sub_select subQuery
            return cmts
    return $ Cmts comments

我也注意到in_ operator,但我不知道如何使用它,也不知道它是否比sub_select 更合适。

我错过了什么?语法是否正确?谢谢。

【问题讨论】:

  • 不相关,但SELECT * ... 风格不好:)。为什么不直接使用 SQLite 或任何其他 SQL DB?它们的类型都很好;)
  • @Igor 糟糕的风格是指不只选择所需的内容?根据您的第二个问题,我已经编辑了问题以指定我使用persistentpostgresql
  • @Igor Esqueleto 旨在维护 Haskell 和 SQL 之间的类型安全。如果您使用纯 SQL,编译器不能也不会检查类型是否在两个世界之间正确编组。
  • @Igor,@chi 说的就是我要转esqueleto的原因。
  • 无论如何,快速浏览一下文档:sub_select 只返回 one 值,因此它看起来是错误的工具。我会尝试 in_subList_select 来紧密匹配 SQL。

标签: haskell persistent servant esqueleto


【解决方案1】:

你会想要这样的东西

getCommentsForArticle slug = do
  c <- select $ from $ \cmts -> do
         let a = subList_select $ from $ \arts -> do
                 where_ $ arts ^. ArticleSlug ==. val slug
                 return $ arts ^. ArticleId
         where_ $ cmts ^. CommentArticleId `in_` a
         return cmts
  return $ Cmts c

【讨论】:

  • 需要在subList_select from 中有一个$,例如subList_select $ from,否则将失败。请修复
猜你喜欢
  • 1970-01-01
  • 2011-06-02
  • 1970-01-01
  • 1970-01-01
  • 2011-03-31
  • 1970-01-01
  • 2018-09-14
  • 2015-06-11
  • 2011-12-15
相关资源
最近更新 更多