【问题标题】:SQLAlchemy | Limit join result to one row for one-to-many relationshipSQL炼金术 |将连接结果限制为一对多关系的一行
【发布时间】:2018-04-30 22:53:06
【问题描述】:

我有两个实体:项目和学生列表。 一个项目可以有多个学生列表。

我正在尝试加入项目中的学生列表,并且仅根据学生列表的自定义顺序返回每个项目的第一行。

尝试的子查询:

_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()

上面我定义了基于学生列表状态 ID 的自定义排序。该函数返回子查询,然后我尝试加入下面的项目外部查询(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 entry still present in correlated subquery

【问题讨论】:

    标签: python mysql sqlalchemy flask-sqlalchemy


    【解决方案1】:

    我有类似的问题。 解决方法是使用 LATERAL sqlalchemy 方法:

    subquery = select([student_list.c.project_id, student_list.c.student_list_id])\
                   .where(student_list.c.project_id == project.project_id)\
                   .limit(1)\
                   .lateral('students')
    query = select([project.c.project_name, subquery.c.project_id, subquery.c.student_list_id])\
                   .select_from(project.join(subquery))
    
    

    【讨论】:

      【解决方案2】:

      终于解决了这个问题。当需要使用 SQLAlchemy 和 mySQL 对组进行自定义排序时,希望这可以帮助其他人尝试解决 first-n-per-group 问题。

      首先我有这个函数,它返回项目优先级最高的一个 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 函数的结果。

      【讨论】:

        猜你喜欢
        • 2014-10-12
        • 2019-06-28
        • 1970-01-01
        • 1970-01-01
        • 2022-07-18
        • 2020-04-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多