SQL查询:LEFT仅加入返回的交集

时间:2013-06-17 10:09:19

标签: sql left-join

我一直在努力解决我认为简单的SQL查询:

SELECT 
  resource.firstname, 
  resource.lastname, 
  resource.fte, 
  project.name as project_name, 
  role.name as role_name, 
  assignment.startdate, 
  assignment.enddate, 
  assignment.numberofdaysperweek
FROM 
  resource
LEFT JOIN assignment ON resource.id = assignment.resource_id AND assignment.enddate < now()
LEFT JOIN project ON project.id = assignment.project_id 
LEFT JOIN role ON role.id = assignment.role_id

所以我在此查询中有4个表:resourcesassignedprojects,并为该项目提供了特定的role

此查询的问题在于它将返回任何资源+任何具有“已过期”赋值的资源(assignment.enddate&lt; now())的数据。但是,我需要将此条件仅应用于该资源的LAST分配。 您是否知道如何实现这一目标?

2 个答案:

答案 0 :(得分:2)

大多数数据库都支持row_number()功能。使用这样的功能,您可以将其处理为:

SELECT 
  resource.firstname, 
  resource.lastname, 
  resource.fte, 
  project.name as project_name, 
  role.name as role_name, 
  assignment.startdate, 
  assignment.enddate, 
  assignment.numberofdaysperweek
FROM 
  resource
LEFT JOIN (select a.*,
                  row_number() over (partition by resource_id order by enddate) as seqnum
           from assignment a
           where assignment.enddate < now()
          ) assignment
     ON resource.id = assignment.resource_id AND seqnum = 1
LEFT JOIN project ON project.id = assignment.project_id 
LEFT JOIN role ON role.id = assignment.role_id;

row_number()函数为resource_idpartition by resource_id)的每个值中的分配分配一个序号。然后对它们进行排序,以便具有最新enddate的那个获得值1(order by enddate)。

答案 1 :(得分:1)

要将您的分配限制为仅限每个资源的最新分配,您需要找到每个resource_id的最新开始日期,并INNER JOIN返回分配表;

SELECT  assignment.*
FROM    assignment
        INNER JOIN
        (   SELECT  assignment.resource_id, 
                    MAX(assignment.StartDate) AS StartDate
            FROM    assignment
            GROUP BY assignment.resource_id
        ) MaxAssignment
            ON assignment.resource_id = MaxAssignment.resource_id
            AND assignment.StartDate = MaxAssignment.StartDate;

由于您只需要LEFT JOIN,因此您需要将上述全部内容移动到子查询中,并将整个子查询LEFT JOIN移回主查询:

SELECT  resource.firstname, 
        resource.lastname, 
        resource.fte, 
        project.name as project_name, 
        role.name as role_name, 
        assignment.startdate, 
        assignment.enddate, 
        assignment.numberofdaysperweek
FROM    resource
        LEFT JOIN 
        (   SELECT  assignment.*
            FROM    assignment
                    INNER JOIN
                    (   SELECT  assignment.resource_id, 
                                MAX(assignment.StartDate) AS StartDate
                        FROM    assignment
                        GROUP BY assignment.resource_id
                    ) MaxAssignment
                        ON assignment.resource_id = MaxAssignment.resource_id
                        AND assignment.StartDate = MaxAssignment.StartDate
        ) assignment
            ON resource.id = assignment.resource_id 
            AND assignment.enddate < now()
        LEFT JOIN project 
            ON project.id = assignment.project_id 
        LEFT JOIN role 
            ON role.id = assignment.role_id;

如果我误解了您对每个资源的“最后”分配的解释,您可能需要修改子查询MaxAssignmen内的aggergate和内部联接返回assignments,但同样如此校长应该适用。

修改

出于某种原因,我认为这是MySQL,但下面评论中的错误消息看起来更像Postgresql,在这种情况下,您可以使用ROW_NUMBER将其限制为仅限每个资源的最后一个分配: / p>

SELECT  resource.firstname, 
        resource.lastname, 
        resource.fte, 
        project.name as project_name, 
        role.name as role_name, 
        assignment.startdate, 
        assignment.enddate, 
        assignment.numberofdaysperweek
FROM    resource
        LEFT JOIN 
        (   SELECT  *, ROW_NUMBER() OVER(PARTITION BY ResourceID ORDER BY StartDate DESC) RN
            FROM    assignment
        ) assignment
            ON resource.id = assignment.resource_id 
            AND RN = 1
            AND assignment.enddate < now()
        LEFT JOIN project 
            ON project.id = assignment.project_id 
        LEFT JOIN role 
            ON role.id = assignment.role_id;