Esqueleto: присоединиться к подзапросу (используя subList_select)

Я пытаюсь перевести следующий 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),

2 ответа

Я боролся с похожей проблемой.

Вы можете использовать «экспериментальный» модуль библиотеки, который немного мощнее обычного 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)

Некоторое добавление / удаление justs в onпункт может быть необходим! Я нашел то, что мне было нужно, очень не интуитивно понятным.

Также будьте осторожны при использовании max_ (esqueleto) а не max (стандартная библиотека), иначе у вас будут другие запутанные ошибки!

Я думаю, я могу использовать следующее, которое должно быть семантически идентичным (вдохновленный этим ответом):

$ 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_...

Другие вопросы по тегам