当前位置: 首页 > 面试题库 >

组成Database.Esqueleto查询,条件联接和计数

宰父飞白
2023-03-14
问题内容

如何以模块化方式构成Database.Esqueleto查询,以便在定义“基本”查询和相应的结果集之后,可以通过添加其他内部联接和where表达式来限制结果集。

另外,由于基本查询不是照此执行的,而是使用LIMIT和OFFSET的修改版本,因此如何将返回实体列表(或字段元组)的基本查询转换为对结果集进行计数的查询。

Yesod书中采用的以下不正确的Haskell代码段有望阐明我的目标。

{-# LANGUAGE QuasiQuotes, TemplateHaskell, TypeFamilies, OverloadedStrings #-}
{-# LANGUAGE GADTs, FlexibleContexts #-}
import qualified Database.Persist as P
import qualified Database.Persist.Sqlite as PS
import Database.Persist.TH
import Control.Monad.IO.Class (liftIO)
import Data.Conduit
import Control.Monad.Logger
import Database.Esqueleto
import Control.Applicative

share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
    name String
    age Int Maybe
    deriving Show
BlogPost
    title String
    authorId PersonId
    deriving Show
Comment
    comment String
    blogPostId BlogPostId
|]

main :: IO ()
main = runStdoutLoggingT $ runResourceT $ PS.withSqliteConn ":memory:" $ PS.runSqlConn $ do
    runMigration migrateAll

    johnId <- P.insert $ Person "John Doe" $ Just 35
    janeId <- P.insert $ Person "Jane Doe" Nothing

    jackId <- P.insert $ Person "Jack Black" $ Just 45
    jillId <- P.insert $ Person "Jill Black" Nothing

    blogPostId <- P.insert $ BlogPost "My fr1st p0st" johnId
    P.insert $ BlogPost "One more for good measure" johnId
    P.insert $ BlogPost "Jane's" janeId

    P.insert $聽Comment "great!" blogPostId

    let baseQuery = select $ from $ \(p `InnerJoin` b) -> do聽
        on (p ^. PersonId ==. b ^. BlogPostAuthorId)
        where_ (p ^. PersonName `like` (val "J%"))
        return (p,b)

    -- Does not compile
    let baseQueryLimited = (,) <$> baseQuery <*> (limit 2)

    -- Does not compile
    let countingQuery = (,) <$> baseQuery <*> (return countRows)

    -- Results in invalid SQL 
    let commentsQuery = (,) <$> baseQuery
                <*> (select $聽from $ \(b `InnerJoin` c) -> do
                        on (b ^. BlogPostId ==. c ^. CommentBlogPostId)
                        return ())

    somePosts <- baseQueryLimited
    count <- countingQuery
    withComments <- commentsQuery
    liftIO $ print somePosts
    liftIO $ print ((head count) :: Value Int)
    liftIO $ print withComments
    return ()

问题答案:

对于LIMITCOUNT,hammar的答案是完全正确的,因此我不会深入研究它们。我只是重申一下,一旦使用,select您将无法再次以任何方式更改查询。

对于JOINs,当前您无法INNER JOIN使用在其他from(nor (FULL|LEFT|RIGHT) OUTER JOIN)中定义的查询执行。但是,您 可以 执行隐式联接。例如,如果您已定义:

baseQuery = 
  from $ \(p `InnerJoin` b) -> do 
  on (p ^. PersonId ==. b ^. BlogPostAuthorId)
  where_ (p ^. PersonName `like` val "J%")
  return (p, b)

然后您可能会说:

commentsQuery = 
  from $ \c -> do
  (p, b) <- baseQuery
  where_ (b ^. BlogPostId ==. c ^. CommentBlogPostId)
  return (p, b, c)

然后,Esqueleto会生成以下内容:

SELECT ...
FROM Comment, Person INNER JOIN BlogPost
ON    Person.id = BlogPost.authorId
WHERE Person.name LIKE "J%"
AND   BlogPost.id = Comment.blogPostId

不漂亮,但可以完成INNER JOINs的工作。如果需要执行a,OUTER JOIN则必须重构代码,以使所有OUTERJOINs都相同from(请注意,您可以在OUTER JOINs之间进行隐式联接就可以了)。



 类似资料:
  • subcompany.hbm.xml 子单位表 branch.java 指定表 我需要帮助编写条件查询使用提供的SQL。

  • 问题内容: 在带有mysql的Rails 3中,假设我有两个模型,Customers和Purchases,显然是purchase_to customer。我想找到2个或更多订单的所有客户。我可以简单地说: 有效地,上面的行查询Customer.all和Purchase.all的大小,然后在ruby中进行“选择”类型的处理。在大型数据库中,我更希望避免在ruby中进行所有这种“选择”计算,而让mys

  • 问题内容: 我绝对是SQL的新手,我一直在努力用Postgresql中的以下表结构编写一个复杂的查询: 查询的目的是获取每个用户的报告类型数量,并将其显示在一列中。有三种不同类型的报告。 使用group-by的简单查询将解决问题,但将其显示在不同的行中: 问题答案:

  • 我想知道是否可以将一个实体配置为自动从另一个实体加载数据。前任。 和 当findby、findbyone等访问accountsUsers时,是否可以设置accountsUsers以自动加载所有帐户数据。关系为accountsUsers.userid=accounts.id。 如果没有,我将如何在使用原则的连接中做到这一点。我知道如何使用纯原始sql。 选择*从帐户a左加入帐户用户ba.id=b.u

  • 如何使用Laravel的查询构建器构建相同的查询(如果可能的话)是使用Eloquent更好,还是应该使用DB::Select?

  • 有没有办法在没有显式连接的实体上编写条件查询?通过显式连接,我的意思是数据库中的两个表没有外键关系,但一些列需要从两个表中提取,因此在查询中需要连接。我知道具有join的查询可以用‘In’子句编写,而条件查询可以用‘In’条件编写。我已经写了这种情况下的HQL,但请告诉我如何编写这种情况下的标准查询。 先谢谢了