如何实现这个SQL查询?最小(日期1)和最大日期(日期2)

时间:2016-01-19 16:31:14

标签: sql-server

这就是我的表格的样子。我想为每个mcode只显示一行。 这里的规则是 对于AType =开始里程碑,我们必须采取MIN(StartDate)和for AType =完成里程碑考虑最大值(EndDate)。

PID AId      Mcode     AType           StartDate                     EndDate
1   ABC1    PM105   Start Milestone    2013-08-12 00:00:00.000         NULL
1   ABC2    PM200   Start Milestone    2015-06-22 00:00:00.000         NULL
1   ABC3    PM200   Start Milestone    2014-08-25 00:00:00.000         NULL
1   ABC4    PM200   Start Milestone    2014-09-29 00:00:00.000         NULL
1   ABC5    PM200   Start Milestone    2014-08-11 00:00:00.000         NULL
1   ABC6    PM200   Start Milestone    2014-08-11 00:00:00.000         NULL
1   ABC7    PM235   Finish Milestone       NULL                      2015-11-10 00:00:00.000
1   ABC8    PM235   Finish Milestone       NULL                      2015-11-18 00:00:00.000
1   ABC9    PM235   Finish Milestone       NULL                      2015-11-10 00:00:00.000
1   ABC10   PM235   Finish Milestone       NULL                      2015-09-03 00:00:00.000
1   ABC11   PM235   Finish Milestone       NULL                      2016-02-25 00:00:00.000
1   ABC12   WM310   Finish Milestone       NULL                      2017-09-29 00:00:00.000 

我的输出应该如下:

 PID    AId      Mcode     AType           StartDate                     EndDate
    1   ABC1    PM105   Start Milestone    2013-08-12 00:00:00.000         NULL
    1   ABC6    PM200   Start Milestone    2014-08-11 00:00:00.000         NULL
    1   ABC11   PM235   Finish Milestone       NULL                      2016-02-25 00:00:00.000
    1   ABC12   WM310   Finish Milestone       NULL                      2017-09-29  00:00:00.000

您可以使用以下sql脚本:

Create table MilestoneData
(
ProjectID int,
ActivityId varchar(10),
MileStoneCode varchar(5),
ActivityType varchar(50),
StartDate datetime,
EndDate Datetime)


insert into MilestoneData values(1,'ABC1','PM105','Start Milestone','2013-08-12 00:00:00.000',NULL)

insert into MilestoneData values(1,'ABC2','PM200','Start Milestone','2015-06-22 00:00:00.000',NULL)
insert into MilestoneData values(1,'ABC3','PM200','Start Milestone','2014-08-25 00:00:00.000',NULL)
insert into MilestoneData values(1,'ABC4','PM200','Start Milestone','2014-09-29 00:00:00.000',NULL)
insert into MilestoneData values(1,'ABC5','PM200','Start Milestone','2014-08-11 00:00:00.000',NULL)
insert into MilestoneData values(1,'ABC6','PM200','Start Milestone','2014-08-11 00:00:00.000',NULL)

insert into MilestoneData values(1,'ABC7','PM235','Finish Milestone',NULL,'2015-11-10 00:00:00.000')
insert into MilestoneData values(1,'ABC8','PM235','Finish Milestone',NULL,'2015-11-18 00:00:00.000')
insert into MilestoneData values(1,'ABC9','PM235','Finish Milestone',NULL,'2015-11-10 00:00:00.000')
insert into MilestoneData values(1,'ABC10','PM235','Finish Milestone',NULL,'2015-09-03 00:00:00.000')
insert into MilestoneData values(1,'ABC11','PM235','Finish Milestone',NULL,'2016-02-25 00:00:00.000')

insert into MilestoneData values(1,'ABC12','WM310','Finish Milestone',NULL,'2017-09-29 00:00:00.000')

4 个答案:

答案 0 :(得分:3)

试试这样:

WITH DistinctMileStoneCodes AS
(
    SELECT DISTINCT ProjectID,MileStoneCode
    FROM MilestoneData 
)

SELECT dms.ProjectID
      ,dms.MileStoneCode 
      ,StartAndFinish.*
FROM DistinctMileStoneCodes AS dms
CROSS APPLY
(
          SELECT TOP 1 x.ActivityId,x.ActivityType,x.StartDate,x.EndDate FROM MilestoneData AS x WHERE x.ProjectID=dms.ProjectID AND x.MileStoneCode=dms.MileStoneCode AND  ActivityType='Start Milestone' ORDER BY StartDate ASC
    UNION SELECT TOP 1 x.ActivityId,x.ActivityType,x.StartDate,x.EndDate FROM MilestoneData AS x WHERE x.ProjectID=dms.ProjectID AND x.MileStoneCode=dms.MileStoneCode AND  ActivityType='Finish Milestone' ORDER BY EndDate DESC
) AS StartAndFinish

结果

ProjectID   MileStoneCode  ActivityID   ActivityType      StartDate   EndDate
1           PM105          ABC1         Start Milestone   2013-08-12    NULL
1           PM200          ABC5         Start Milestone   2014-08-11    NULL
1           PM235          ABC11        Finish Milestone    NULL      2016-02-25    
1           WM310          ABC12        Finish Milestone    NULL      2017-09-29

答案 1 :(得分:2)

解决此问题的一种方法是使用窗口函数ROW_NUMBER对记录进行排名。

在这里,我添加了一个在CTE内计算的起点和终点排名。我使用CTE有两个原因。首先,您可以更轻松地独立运行查询并查看其工作原理。其次,您不能直接在WHERE子句中使用窗口函数。

WHERE子句使用CASE表达式来选择要过滤的排名字段。在这两种情况下,我们都希望得到最低等级(1)。

示例

WITH Ranked AS
    (
        /* CTE ranks each record based on Start and End dates.
         */
        SELECT
            ROW_NUMBER() OVER (PARTITION BY MileStoneCode ORDER BY StartDate ASC)    AS StartRank,
            ROW_NUMBER() OVER (PARTITION BY MileStoneCode ORDER BY EndDate DESC)    AS EndRank,
            ms.*
        FROM
            MilestoneData AS ms
    )
SELECT
    * 
FROM
    Ranked 
WHERE    
    /* Case expression returns only the first ranked record, 
     * where ranking field is based on MileStonCode.
     */
    CASE MileStoneCode
        WHEN 'Start Milestone' THEN StartRank
        ELSE EndRank
    END = 1
;

值得强调的是,在使用CTE时,必须使用分号终止任何前面的语句。

答案 2 :(得分:1)

你想要这样的东西:

SELECT MileStoneCode, 
       MIN(StartDate) 
FROM MilestoneData 
WHERE ActivityType = 'Start Milestone' 
GROUP BY MileStoneCode;

SELECT MileStoneCode, 
       MAX(EndDate) 
FROM MilestoneData 
WHERE ActivityType = 'Finish Milestone' 
GROUP BY MileStoneCode;

点击此处的小提琴:http://sqlfiddle.com/#!9/edb508/7

答案 3 :(得分:1)

这应该产生你正在寻找的东西(根据你提供的创建脚本运行它):

SELECT projectID, ActivityId, MilestoneCode, ActivityType, startdate, 
enddate
FROM MilestoneData
WHERE MilestoneCode + Right(activityId,  Len(activityid)-3) + Cast(startdate AS VARCHAR) IN 
(SELECT MilestoneCode + Cast(Max(Cast(Right(activityid, Len(activityid)-3) AS INT)) AS VARCHAR) + Cast(Min(startdate) AS VARCHAR)
FROM MilestoneData
WHERE activityType = 'Start Milestone'
GROUP BY milestonecode)
UNION SELECT projectID, ActivityId, MilestoneCode, ActivityType, startdate, enddate
FROM MilestoneData
WHERE MilestoneCode + Right(activityId,  Len(activityid)-3) + Cast(enddate AS VARCHAR) IN 
(SELECT MilestoneCode + Cast(Max(Cast(Right(activityid, Len(activityid)-3) AS INT)) AS VARCHAR) + Cast(Max(enddate) AS VARCHAR)
FROM MilestoneData
WHERE activityType = 'Finish Milestone'
GROUP BY milestonecode)

编辑:更正声明