【问题标题】:Esqueleto: join on subquery (using subList_select)Esqueleto:加入子查询(使用 subList_select)
【发布时间】:2017-12-16 20:29:54
【问题描述】:

我正在尝试将以下 SQL 转换为 Esqueleto:

SELECT id, task_id, author_id
FROM scenario
INNER JOIN ( SELECT task_id as tId, author_id as aId, MAX(last_update) as lastUp
             FROM scenario
             GROUP BY task_id, author_id
           ) t
      ON task_id = tId AND author_id = aId AND last_update = lastUp

要进行子查询,您必须使用subList_select

我想不出一种将它与以下模式匹配结合起来的方法:

from $ \(s `InnerJoin` ?subQueryhere?) -> do ...

所以我尝试改用where_

where_ (s ^. ScenarioTaskId ==. (subList_select $
         from $ \s' -> do
         groupBy (s' ^. ScenarioTaskId, s' ^. ScenarioAuthorId)
         return s'
       ) ^. ScenarioTaskId)

但是,由于 subList_select 返回的是 expr (ValueList a) 而不是 expr (Entity Scenario),因此无法编译。

【问题讨论】:

    标签: sql haskell yesod esqueleto


    【解决方案1】:

    我也在为类似的事情苦苦挣扎。

    您可以使用库的“实验”模块(https://hackage.haskell.org/package/esqueleto-3.4.2.2/docs/Database-Esqueleto-Experimental.html 上的文档),它比普通 esqueleto 更强大(并且与普通 esqueleto 略有不同)。

    主要区别在于from - 你明确地告诉它你正在加入什么,并且有很多选择。当你想谈论表格时,你还需要打开一个额外的扩展来使用@TableName 标签。

    我很想把所有东西都改写成实验性的,除了它产生的错误更难解决,因为你最终会使用更多的 do 表示法。

    无论如何,这是您可能需要的近似值:

        (scenario :& (taskId, authorId) <- 
          from $ Table @Scenario `InnerJoin` SubQuery (do
            scenario <- from $ Table @Scenario   
            groupBy (scenario ^. ScenarioTaskId, scenario ^. ScenarioAuthorId)
            return (scenario ^. ScenarioTaskId, scenario ^. ScenarioAuthorId, max_(scenario ^. ScenarioLastUpdate))
            ) 
          `on` (\(scenario :& (taskId, authorId)) -> 
            (just (scenario ^. ScenarioTaskId) ==. just taskId) &&.
            (just (scenario ^. ScenarioAuthorId) ==. authorId) &&.
            (just (scenario ^. ScenarioLastUpdate) ==. lastUp)
          )
        return (scenario ^. ScenarioId, taskId, authorId)
    

    可能需要在on 子句中添加/删除justs!我发现我需要的东西非常不直观。

    还要小心你使用max_(esqueleto)而不是max(标准库),否则你会遇到其他令人困惑的错误!

    【讨论】:

      【解决方案2】:

      我想我可以使用以下语义相同的内容(受this answer 启发):

      $ select
      $ from $ \( s `LeftOuterJoin` ms ) -> do
              on ( just (s ^. ScenarioAuthorId)  ==. ms ?. ScenarioAuthorId &&.
                   just (s ^. ScenarioTaskId)    ==. ms ?. ScenarioTaskId   &&.
                   just (s ^. ScenarioLastUpdate) <. ms ?. ScenarioLastUpdate )
        where_ (isNothing (ms ?. ScenarioId))
      

      仍然让我感到困惑的是,Esqueleto 显然只支持与 in_ 结合使用的具有多个结果的子查询...

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-02-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多