如何使用 Esqueleto 执行“SELECT ... IN (SELECT ...)”?
Posted
技术标签:
【中文标题】如何使用 Esqueleto 执行“SELECT ... IN (SELECT ...)”?【英文标题】:How to do a "SELECT ... IN (SELECT ...)" using Esqueleto? 【发布时间】: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 糟糕的风格是指不只选择所需的内容?根据您的第二个问题,我已经编辑了问题以指定我使用persistent
和postgresql
。
@Igor Esqueleto 旨在维护 Haskell 和 SQL 之间的类型安全。如果您使用纯 SQL,编译器不能也不会检查类型是否在两个世界之间正确编组。
@Igor,@chi 说的就是我要转esqueleto
的原因。
无论如何,快速浏览一下文档:sub_select
只返回 one 值,因此它看起来是错误的工具。我会尝试 in_
和 subList_select
来紧密匹配 SQL。
【参考方案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
,否则将失败。请修复以上是关于如何使用 Esqueleto 执行“SELECT ... IN (SELECT ...)”?的主要内容,如果未能解决你的问题,请参考以下文章