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

Sql server 如何实现这个SQL查询?最小值(日期1)和最大值(日期2),sql-server,Sql Server,这就是我的表的外观。我只想为每个mcode显示一行。 这里的规则是 对于AType=开始里程碑,我们必须采用MIN(开始日期)和 Atype =完成里程碑考虑max(EdDATE).< /P> 我的输出应该如下所示: PID AId Mcode AType StartDate EndDate 1 ABC1 PM105 Start Milestone 2013-08-12 00:00:

这就是我的表的外观。我只想为每个mcode显示一行。 这里的规则是 对于AType=开始里程碑,我们必须采用MIN(开始日期)和 Atype =完成里程碑考虑max(EdDATE).< /P> 我的输出应该如下所示:

 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')

你想要这样的东西:

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;
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

检查这里的小提琴:

你想要这样的东西:

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;
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

检查这里的提琴:

这应该会生成您想要的内容(根据您提供的创建脚本运行它):


EDIT:corrected语句

这应该会生成您要查找的内容(根据您提供的创建脚本运行):

编辑:更正的语句

尝试如下操作:

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;
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
试着这样做:

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;
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

一种方法是使用窗口函数对记录进行排序

在这里,我添加了一个开始和结束等级,在一个。我使用CTE有两个原因。首先,您可以更轻松地独立运行查询并了解其工作原理。其次,不能在WHERE子句中直接使用窗口函数

WHERE子句使用表达式选择要筛选的排名字段。在这两种情况下,我们都需要最低等级(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时,前面的任何语句都必须以分号终止。

一种方法是使用窗口函数对记录进行排序

在这里,我添加了一个开始和结束等级,在一个。我使用CTE有两个原因。首先,您可以更轻松地独立运行查询并了解其工作原理。其次,不能在WHERE子句中直接使用窗口函数

WHERE子句使用表达式选择要筛选的排名字段。在这两种情况下,我们都需要最低等级(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时,前面的任何语句都必须以分号终止。

MCode在示例数据中有5个ActivityID。您如何选择返回哪个(在您的预期输出中是ABC6)。样本数据中的MCODE比预期的输出要多,你能解释为什么吗?这里的规则是Atype=开始里程碑,我们必须取Min(StaseDead),而Atype=完成里程碑考虑Max(EnDeDATE),每个MCODE都是一行。MCODE既有起点又有终点里程碑?因为你是新来的,所以请允许我一个提示:只要你不接受一个答案(从你的角度来看是最好的),这仍然是开放的,像我这样的人会继续回来看看是否有新的东西。因此,请务必对答案进行投票,并在被接受的最佳答案上打勾(如果有一个答案能够真正解决您的问题!),同时请查看您以前的问题……这里有一个方便的答案。MCode在示例数据中有5个ActivityID。您如何选择返回哪个(在您的预期输出中是ABC6)。样本数据中的MCODE比预期的输出要多,你能解释为什么吗?这里的规则是Atype=开始里程碑,我们必须取Min(StaseDead),而Atype=完成里程碑考虑Max(EnDeDATE),每个MCODE都是一行。MCODE既有起点又有终点里程碑?因为你是新来的,所以请允许我一个提示:只要你不接受一个答案(从你的角度来看是最好的),这仍然是开放的,像我这样的人会继续回来看看是否有新的东西。因此,请务必对答案进行投票,并在被接受的最佳答案上打勾(如果有一个答案真的解决了您的问题!),同时也请查看您以前的问题……这里有一个方便的答案。我不想这么说,尤其是当代码已经很好地呈现,但它不会返回ActivityId时。@destination data,good catch,thx,编辑此。。。投你的票,这也很好!我也投了你的票。我厌倦了交叉应用自己,但没有想到结合工会。很好的方法。我不想这么说,尤其是当代码被很好地呈现时,但它不会返回ActivityId。@目标数据,很好的捕获,thx,编辑了这个。。。投你的票,这也很好!我也投了你的票。我厌倦了交叉应用自己,但没有想到结合工会。好办法。