如何在一对多查询的中间选择多个字段的最大值

时间:2013-12-27 21:07:07

标签: sql sql-server tsql

所有

我在下面有这个查询,这是一对多的关系。

关系就是这样,一个故事可以有多个任务(1> M)每个任务可以有多个时间条目(M-M)

我希望在任务部分中第一次出现3个字段,并为每个故事取消其余部分。所以例如;

Story 1234
Tasks 12, 13, 14,15
Time entry 120, 121, 134, 135 etc....

任务OptimisticEstimate,ProbableEstimate和Pessimistic Estimate中有3个字段,当时间条目表链接到查询时,它会在任务级别重复(应该如此)。

我希望为每个任务获得第一次出现的这些字段,并将任何其他事件保留为NULL,以便在我们总结时估计不会与从时间输入的小时数相加。

希望这很清楚。

WITH
WorkItem_CTE AS
    (-- Child Level (Task)
    SELECT   wi1.AreaID
            ,a.Name AS AreaName
            ,wi1.ProjectID
            ,wi1.IterationID
            -- Work Items
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
            ,wi1.WorkItemID
            ,wi1.[Type] AS WorkItemType
            ,wi1.Name AS WorkItemName
            ,wi1.[Status] AS WorkItemStatus
            ,wi1.[Priority] AS WorkItemPriority
            ,wi1.Complexity
            ,wi1.Estimate
            -- Tasks
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
            ,wi2.WorkItemID AS TaskID
            ,wi2.Name AS TaskName
            ,wi2.[Status] AS TaskStatus
            ,wi2.AssignedTo  AS TaskAssignedTo
            ,wi2.EstimateOptimistic
            ,Case When wi2.EstimateProbable IS NULL  Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
            ,wi2.EstimatePessimistic
            ,wi2.WorkCompleted
            ,wi2.WorkRemaining
    FROM    dbo.WorkItem wi1 WITH (NOLOCK)
            INNER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
                ON wi1.WorkItemID = wi2.ParentID
                AND wi2.[Status] <> 'Deleted'
            LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
                ON wi1.AreaID = a.AreaID
            --LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
            --  ON wi1.ProjectID = p.ProjectID
    WHERE   wi1.[Status] <> 'Deleted'
    UNION ALL
    -- Parent level (Story, Bug, Feedback)
    SELECT   wi1.AreaID
            ,a.Name AS AreaName
            ,wi1.ProjectID
            ,wi1.IterationID
            -- Work Items
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
            ,wi1.WorkItemID
            ,wi1.[Type] AS WorkItemType
            ,wi1.Name AS WorkItemName
            ,wi1.[Status] AS WorkItemStatus
            ,wi1.[Priority] AS WorkItemPriority
            ,wi1.Complexity
            ,wi1.Estimate
            -- Tasks
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
            ,wi2.WorkItemID AS TaskID
            ,wi2.Name AS TaskName
            ,wi2.[Status] AS TaskStatus
            ,wi2.AssignedTo  AS TaskAssignedTo
            ,wi2.EstimateOptimistic
            ,Case When wi2.EstimateProbable IS NULL  Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
            ,wi2.EstimatePessimistic
            ,wi2.WorkCompleted
            ,wi2.WorkRemaining
    FROM    dbo.WorkItem wi1 WITH (NOLOCK)
            LEFT OUTER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
                ON wi1.WorkItemID = wi2.ParentID
                AND wi2.[Status] <> 'Deleted'
            LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
                ON wi1.AreaID = a.AreaID
    WHERE   wi1.[Type] <> 'Task'
    AND     wi1.[Status] <> 'Deleted'
    AND     wi2.ParentID IS NULL
    ),
--Time Entry for Tasks  
TimeEntry_CTE As
(SELECT te.WorkItemID
      ,te.ProjectID
      ,te.Date
      ,te.Hours
      ,te.CreatedBy
      ,te.CreatedDateUtc
      ,te.LastModifiedBy
      ,te.LastModifiedDateUtc
      ,te.Note
  FROM TimeEntry te
  ) 
SELECT   wi.AreaID
        ,wi.AreaName
        ,wi.ProjectID
        ,p.Name AS ProjectName
        ,wi.WorkItemCreatedDTS
        ,wi.WorkItemID
        ,wi.WorkItemType
        ,wi.WorkItemName
        ,wi.WorkItemStatus
        ,wi.WorkItemPriority
        ,wi.Complexity
        ,wi.Estimate AS StoryEstimate
        ,wi.TaskCreatedDTS
        ,wi.TaskID
        ,wi.TaskName
        ,wi.EstimateOptimistic
        ,wi.EstimateProbable
        ,wi.EstimatePessimistic
        ,wi.TaskStatus
        ,wi.TaskAssignedTo
        ,wi.WorkCompleted
        ,wi.WorkRemaining
        ,te.WorkItemID as TimeWorkItemID
        ,te.ProjectID
        ,te.Date
        ,te.Hours
        ,te.CreatedBy
        ,te.CreatedDateUtc
        ,te.LastModifiedBy
        ,te.LastModifiedDateUtc
        ,te.Note
FROM    WorkItem_CTE wi WITH (NOLOCK)
        LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
            ON wi.ProjectID = p.ProjectID
        inner Join TimeEntry_CTE te With (nolock)
            ON wi.TaskID = te.WorkItemID

先谢谢你的帮助。

根据建议修改代码。更近但不太正确。

WITH
WorkItem_CTE AS
    (-- Child Level (Task)
    SELECT   wi1.AreaID
            ,a.Name AS AreaName
            ,wi1.ProjectID
            ,wi1.IterationID
            -- Work Items
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
            ,wi1.WorkItemID
            ,wi1.[Type] AS WorkItemType
            ,wi1.Name AS WorkItemName
            ,wi1.[Status] AS WorkItemStatus
            ,wi1.[Priority] AS WorkItemPriority
            ,wi1.Complexity
            ,wi1.Estimate
            -- Tasks
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
            ,wi2.WorkItemID AS TaskID
            ,wi2.Name AS TaskName
            ,wi2.[Status] AS TaskStatus
            ,wi2.AssignedTo  AS TaskAssignedTo
            ,wi2.EstimateOptimistic
            ,Case When wi2.EstimateProbable IS NULL  Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
            ,wi2.EstimatePessimistic
            ,wi2.WorkCompleted
            ,wi2.WorkRemaining
    FROM    dbo.WorkItem wi1 WITH (NOLOCK)
            INNER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
                ON wi1.WorkItemID = wi2.ParentID
                AND wi2.[Status] <> 'Deleted'
            LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
                ON wi1.AreaID = a.AreaID
            --LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
            --  ON wi1.ProjectID = p.ProjectID
    WHERE   wi1.[Status] <> 'Deleted'
    UNION ALL
    -- Parent level (Story, Bug, Feedback)
    SELECT   wi1.AreaID
            ,a.Name AS AreaName
            ,wi1.ProjectID
            ,wi1.IterationID
            -- Work Items
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi1.CreatedDateUtc) AS WorkItemCreatedDTS
            ,wi1.WorkItemID
            ,wi1.[Type] AS WorkItemType
            ,wi1.Name AS WorkItemName
            ,wi1.[Status] AS WorkItemStatus
            ,wi1.[Priority] AS WorkItemPriority
            ,wi1.Complexity
            ,wi1.Estimate
            -- Tasks
            ,DATEADD(HOUR, DATEDIFF(HOUR, GETUTCDATE(), GETDATE()),wi2.CreatedDateUtc) AS TaskCreatedDTS
            ,wi2.WorkItemID AS TaskID
            ,wi2.Name AS TaskName
            ,wi2.[Status] AS TaskStatus
            ,wi2.AssignedTo  AS TaskAssignedTo
            ,wi2.EstimateOptimistic
            ,Case When wi2.EstimateProbable IS NULL  Then (wi2.EstimateOptimistic + wi2.EstimatePessimistic)/2 Else wi2.EstimateProbable End As EstimateProbable
            ,wi2.EstimatePessimistic
            ,wi2.WorkCompleted
            ,wi2.WorkRemaining
    FROM    dbo.WorkItem wi1 WITH (NOLOCK)
            LEFT OUTER JOIN dbo.WorkItem wi2 WITH (NOLOCK)
                ON wi1.WorkItemID = wi2.ParentID
                AND wi2.[Status] <> 'Deleted'
            LEFT OUTER JOIN dbo.Area a WITH (NOLOCK)
                ON wi1.AreaID = a.AreaID
    WHERE   wi1.[Type] <> 'Task'
    AND     wi1.[Status] <> 'Deleted'
    AND     wi2.ParentID IS NULL
    ),
--Time Entry for Tasks  
TimeEntry_CTE As
(SELECT te.WorkItemID
      ,te.ProjectID
      ,te.Date
      ,te.Hours
      ,te.CreatedBy
      ,te.CreatedDateUtc
      ,te.LastModifiedBy
      ,te.LastModifiedDateUtc
      ,te.Note
  FROM TimeEntry te
  ),
wi_CTE As 
(SELECT  wi.AreaID
        ,wi.AreaName
        ,wi.ProjectID
        ,p.Name AS ProjectName
        ,wi.WorkItemCreatedDTS
        ,wi.WorkItemID
        ,wi.WorkItemType
        ,wi.WorkItemName
        ,wi.WorkItemStatus
        ,wi.WorkItemPriority
        ,wi.Complexity
        ,wi.Estimate AS StoryEstimate
        ,wi.TaskCreatedDTS
        ,wi.TaskID
        ,wi.TaskName
        ,wi.EstimateOptimistic
        ,wi.EstimateProbable
        ,wi.EstimatePessimistic
        ,wi.TaskStatus
        ,wi.TaskAssignedTo
        ,wi.WorkCompleted
        ,wi.WorkRemaining
        ,te.WorkItemID as TimeWorkItemID
        ,te.ProjectID TimeProjectID
        ,te.Date
        ,Sum(te.Hours) Hours
        ,te.CreatedBy
        ,te.CreatedDateUtc
        ,te.LastModifiedBy
        ,te.LastModifiedDateUtc
        ,te.Note
FROM    WorkItem_CTE wi WITH (NOLOCK)
        LEFT OUTER JOIN dbo.Project p WITH (NOLOCK)
            ON wi.ProjectID = p.ProjectID
        inner Join TimeEntry_CTE te With (nolock)
            ON wi.TaskID = te.WorkItemID

--where wi.WorkItemID =94

Group By
         wi.AreaID
        ,wi.AreaName
        ,wi.ProjectID
        ,p.Name
        ,wi.WorkItemCreatedDTS
        ,wi.WorkItemID
        ,wi.WorkItemType
        ,wi.WorkItemName
        ,wi.WorkItemStatus
        ,wi.WorkItemPriority
        ,wi.Complexity
        ,wi.Estimate 
        ,wi.TaskCreatedDTS
        ,wi.TaskID
        ,wi.TaskName
        ,wi.EstimateOptimistic
        ,wi.EstimateProbable
        ,wi.EstimatePessimistic
        ,wi.TaskStatus
        ,wi.TaskAssignedTo
        ,wi.WorkCompleted
        ,wi.WorkRemaining
        ,te.WorkItemID
        ,te.ProjectID
        ,te.Date
        ,te.Hours
        ,te.CreatedBy
        ,te.CreatedDateUtc
        ,te.LastModifiedBy
        ,te.LastModifiedDateUtc
        ,te.Note),

cte AS (SELECT wi_cte.*, ROW_NUMBER() OVER(PARTITION BY WorkItemID, TaskID ORDER BY TimeWorkItemID) RN
              FROM wi_CTE
              )
SELECT 
         AreaID
        ,AreaName
        ,ProjectID
        ,ProjectName
        ,WorkItemCreatedDTS
        ,WorkItemID
        ,WorkItemType
        ,WorkItemName
        ,WorkItemStatus
        ,WorkItemPriority
        ,Complexity
        ,StoryEstimate 
        ,TaskCreatedDTS
        ,TaskID
        ,TaskName
        ,EstimateOptimistic
        ,EstimateProbable
        ,EstimatePessimistic
        ,TaskStatus
        ,TaskAssignedTo
        ,WorkCompleted
        ,WorkRemaining
        ,WorkItemID
        ,ProjectID
        ,Date
        ,Hours
        ,CreatedBy
        ,CreatedDateUtc
        ,LastModifiedBy
        ,LastModifiedDateUtc
        ,Note
        ,RN
        ,SUM(CASE WHEN RN = 1 THEN Hours END) AS SumTime
FROM cte
Where RN=1
GROUP BY 
 AreaID
        ,AreaName
        ,ProjectID
        ,ProjectName
        ,WorkItemCreatedDTS
        ,WorkItemID
        ,WorkItemType
        ,WorkItemName
        ,WorkItemStatus
        ,WorkItemPriority
        ,Complexity
        ,StoryEstimate 
        ,TaskCreatedDTS
        ,TaskID
        ,TaskName
        ,EstimateOptimistic
        ,EstimateProbable
        ,EstimatePessimistic
        ,TaskStatus
        ,TaskAssignedTo
        ,WorkCompleted
        ,WorkRemaining
        ,WorkItemID
        ,ProjectID
        ,Date
        ,Hours
        ,CreatedBy
        ,CreatedDateUtc
        ,LastModifiedBy
        ,LastModifiedDateUtc
        ,Note
        ,RN

我得到了什么

ProjectID   ProjectName WorkItemID  WorkItemType    WorkItemName    EstimateOptimistic  EstimateProbable    EstimatePessimistic RN  SumTime
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   1   8
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   2   4
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   3   4
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   4   4
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   1   4
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   2   4
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   3   4
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   4   8
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   5   3



What I'm Looking for                                    
ProjectID   ProjectName WorkItemID  WorkItemType    WorkItemName    EstimateOptimistic  EstimateProbable    EstimatePessimistic RN  SumTime
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   1   8
11  Data Group  94  Story   Backlog Report with new logic   NULL    NULL    NULL    2   4
11  Data Group  94  Story   Backlog Report with new logic   NULL    NULL    NULL    3   4
11  Data Group  94  Story   Backlog Report with new logic   NULL    NULL    NULL    4   4
11  Data Group  94  Story   Backlog Report with new logic   2   3   4   1   4
11  Data Group  94  Story   Backlog Report with new logic   NULL    NULL    NULL    2   4
11  Data Group  94  Story   Backlog Report with new logic   NULL    NULL    NULL    3   4
11  Data Group  94  Story   Backlog Report with new logic   NULL    NULL    NULL    4   8
11  Data Group  94  Story   Backlog Report with new logic   NULL    NULL    NULL    5   3

希望这有助于澄清我正在努力的目标。

1 个答案:

答案 0 :(得分:0)

我建议使用条件SUM()ROW_NUMBER()函数。

假设上面的查询输出如下数据:

Story, Task, TimeEntry
1234, 12, 120
1234, 12, 121
1234, 12, 134
1234, 13, 135
1234, 13, 120
1234, 13, 121
1234, 13, 134
1234, 14, 135
1234, 14, 120
1234, 14, 121
1234, 14, 134
1234, 14, 135

你可以用这个:

;WITH cte AS (SELECT *, ROW_NUMBER() OVER(PARTITION BY Story, Task ORDER BY TimeEntry) RN
              FROM Table1
              )
SELECT Story, Task, SUM(CASE WHEN RN = 1 THEN TimeEntry END) AS SumTime
FROM cte
GROUP BY Story, Task

演示:SQL Fiddle

对于StoryTask的每个组合,每行都会编号,从1开始,允许您使用RN = 1的条件来避免聚合重复的行。既然您说重复这些值,那么您对ORDER BY的{​​{1}}子句中的内容并不重要。