SQLAlchemy | Ограничить результат объединения одной строкой для отношения один ко многим - PullRequest
0 голосов
/ 01 мая 2018

У меня есть две сущности: проекты и списки студентов. В одном проекте может быть много списков студентов.

Я пытаюсь присоединиться к списку студентов в проекте и возвращать только первую строку для каждого проекта на основе пользовательского порядка списков студентов.

Попытка подзапроса:

_whens = {ProjectStatus.APPROVED: 1, ProjectStatus.REJECTED: 2, 
          ProjectStatus.SUBMITTED: 3, None: 4}
sort_order = case(value=StudentList.student_list_status_id, whens=_whens)

return self._session.query(StudentList).
        filter(StudentList.student_list_id==Project.project_id)
       .order_by(sort_order).limit(1).subquery()

Выше я определяю пользовательский порядок на основе идентификатора статуса списка студентов. Функция возвращает подзапрос, который я затем пытаюсь присоединить к внешнему запросу моего проекта ниже (student_list_subquery ссылается на то, что возвращается выше):

projects = self._session.query(models.Project)
            .filter(models.Project.project_year == year)
            .join(student_list_subquery,
            student_list_subquery.c.project_id==Project.project_id)
            .all()

Ниже приведен соответствующий вывод SQL

FROM project 
LEFT OUTER JOIN (SELECT student_list.project_id AS project_id, 
 student_list.student_list_id AS student_list_id
 FROM student_list, project
 WHERE project.project_id = student_list.project_id 
 ORDER BY CASE student_list.student_list_status_id WHEN 102 THEN 1 
 WHEN 105 THEN 2 WHEN 101 THEN 3 WHEN NULL THEN 4 END
 LIMIT 1) AS anon_1 ON anon_1.project_id = project.project_id

Я использую mySQL, поэтому решения (Distinct On) не будут работать, а также решения row_number / partition либо ...

Кажется, что здесь возникает та же проблема SQLAlchemy: запись FROM все еще присутствует в коррелированном подзапросе

1 Ответ

0 голосов
/ 04 мая 2018

Наконец-то решена проблема. Надеюсь, что это поможет кому-то другому, пытающемуся решить проблему «первый-на-группу», когда требуется пользовательский порядок групп с использованием SQLAlchemy и mySQL.

Сначала у меня есть эта функция, которая возвращает один student_list_status_id с наивысшим приоритетом для проекта (отсюда и фильтр).

@staticmethod
def create_student_list_subquery(session):
    '''create a correlated subquery that will limit result to one student
    list per project with custom sorting to retrieve highest priority list
    per project based on status'''

    sl2=aliased(StudentList)
    list_id = sl2.student_list_status_id.label("list_id")
    _whens = {ProjectStatus.APPROVED: 1, ProjectStatus.REJECTED: 2, 
             ProjectStatus.SUBMITTED: 3, None: 4}
    sort_order = case(value=list_id, whens=_whens)

    return session.query(list_id).filter(sl2.project_id==Project.project_id)
                  .order_by(sort_order)
                  .limit(1)

Я присоединяюсь к статусу проекта, который соответствует student_list_status_id в запросе выше (с псевдонимом ps) для проекта. Затем я могу сортировать по названию статуса проекта, который был моей целью.

self._session.query(models.Project)
        .filter(models.Project.project_year == year)
        .join(ps, ps.project_status_id==student_list_subq)
        .all()

Обратите внимание, что student_list_subq относится к результату функции create_student_list_subquery выше.

...