Sql 按开始和结束时间聚合计划数据

Sql 按开始和结束时间聚合计划数据,sql,sql-server,sql-server-2005,Sql,Sql Server,Sql Server 2005,我有一个棘手的问题,让我挠头有一段时间了。我有一些数据表示“小部件”在不同天数内的交付情况,这些数据细分为半小时的时段 例如(对格式设置表示歉意-尚未完全掌握): 我需要生成一个查询,允许我将这些数据分组到我交付单元的所有不同块中。在上面的例子中,我只需要识别1个区块-23:00到07:00,以及该区块的单位总和(160)。因此,所需的结果将是StartTime、EndTime和TotalNoOfUnits 然而,当我们有不同的交付模式时,复杂性就来了——也许我们有一天可以24小时交付单元 我需

我有一个棘手的问题,让我挠头有一段时间了。我有一些数据表示“小部件”在不同天数内的交付情况,这些数据细分为半小时的时段

例如(对格式设置表示歉意-尚未完全掌握):

我需要生成一个查询,允许我将这些数据分组到我交付单元的所有不同块中。在上面的例子中,我只需要识别1个区块-23:00到07:00,以及该区块的单位总和(160)。因此,所需的结果将是StartTime、EndTime和TotalNoOfUnits

然而,当我们有不同的交付模式时,复杂性就来了——也许我们有一天可以24小时交付单元

我需要能够以上述格式查询数据,并识别所有唯一的StartTime、EndTime和TotalNoOfUnits组合,其中NoOfUnits为0

再次为格式和一个略显杂乱的问题道歉。请问我任何需要澄清的问题

编辑:为了清楚起见,数据将始终在交付的每一天的00:00到23:30之间运行,并且每个半小时的时段将始终存在。对于任何给定的数据集,只有每半小时槽的天数和单位可能有所不同

EDIT2:下面是一个脚本,它将用2天的日程数据填充一个表。这两天的日程安排是一样的。根据我的要求,我希望看到的结果是13:00,00:00,230。正如您将从下面看到的,我的SQL技能不太好,因此令人挠头

declare @DayCount int
declare @HalfHourCount int
declare @HH int
declare @CurrentDate datetime
declare @BaseDate datetime
declare @NoOfUnits int

set @HalfHourCount = 48
set @DayCount = 4
set @BaseDate = '1 Jan 1900'

create table #Schedule
(
Date datetime
, Time datetime
, NoOfUnits int
)

while @DayCount > 0
begin
set @CurrentDate = dateadd(dd, @DayCount * -1, CONVERT(VARCHAR(10),GETDATE(),111))
set @HH = @HalfHourCount

while @HH > 0
begin
    if @HH > 24
        set @NoOfUnits = 10
    else
    begin
        if @DayCount = 4 and @HH < 10
            set @NoOfUnits = 10
        else
            set @NoOfUnits = 0
    end

    insert into #Schedule(Date, Time, NoOfUnits)
    values (@CurrentDate, dateadd(mi, @HH / 2.0 * 60, @BaseDate), @NoOfUnits)

    select @HH = @HH - 1
end

set @DayCount = @DayCount - 1
end

如果我理解正确,请看一下这个例子。如果你有更多的问题,请告诉我

DECLARE @Table TABLE(
        DateVal DATETIME,
        NoOfUnits INT
)

INSERT INTO @Table SELECT '01 Mar 2010 00:30', 0

INSERT INTO @Table SELECT '01 Mar 2010 23:00', 10
INSERT INTO @Table SELECT '01 Mar 2010 23:30', 10
INSERT INTO @Table SELECT '02 Mar 2010 00:30', 10

INSERT INTO @Table SELECT '02 Mar 2010 01:00', 0

INSERT INTO @Table SELECT '02 Mar 2010 02:30', 20
INSERT INTO @Table SELECT '02 Mar 2010 03:30', 30
INSERT INTO @Table SELECT '02 Mar 2010 04:30', 40

INSERT INTO @Table SELECT '02 Mar 2010 05:00', 0

SELECT  *
FROM    @Table

;WITH DateValues AS(
        SELECT  t.DateVal,
                t.NoOfUnits,
                MIN(tNext.DateVal) MinDate
        FROM    @Table t LEFT JOIN
                @Table tNext    ON  t.DateVal < tNext.DateVal
                                AND tNext.NoOfUnits = 0
        WHERE   t.NoOfUnits != 0
        GROUP BY t.DateVal,
                t.NoOfUnits
)
, DateRanges AS(
        SELECT  DateVal StartDate,
                NoOfUnits,

            ISNULL((SELECT MAX(DateVal) FROM @Table WHERE DateVal < MinDate), (SELECT MAX(DateVal) FROM @Table)) EndDateEndDate
        FROM    DateValues
)
SELECT  MIN(StartDate) StartDate,
        SUM(NoOfUnits) TotalUnits,
        EndDate
FROM    DateRanges
GROUP BY EndDate

根据您提供的数据,这应该是可行的。它几乎可以肯定地简化:

;WITH dateCTE
AS
(
        SELECT * 
               ,date + [time] dt
        FROM #Schedule
)
,seqCTE
AS
(
        SELECT NoOfUnits
               ,dt
               ,ROW_NUMBER() OVER (ORDER BY dt) AS rn
        FROM dateCTE               
)
,recCTE
AS
(
        SELECT NoOfUnits
               ,dt
               ,1 AS SEQUENCE
               ,rn
        FROM seqCTE
        WHERE rn = 1

        UNION ALL

        SELECT s.NoOfUnits
              ,s.dt
              ,CASE WHEN (s.NoOfUnits      > 0 
                          AND  r.NoOfUnits > 0
                         )
                      OR (s.NoOfUnits      = 0 
                          AND  r.NoOfUnits = 0
                         )
                    THEN r.SEQUENCE
                    ELSE r.SEQUENCE + 1
               END
              ,s.rn
        FROM recCTE AS r
        JOIN seqCTE AS s
        ON   s.rn = r.rn + 1
)
,summaryCTE
AS
(
        SELECT RIGHT(CONVERT(varchar(23),MIN(dt),120),8)  AS startTime
               ,RIGHT(CONVERT(varchar(23),MAX(dt),120),8) AS endTime
               ,SUM(NoOfUnits) AS NoOfUnits
        FROM recCTE
        GROUP BY SEQUENCE
        HAVING SUM(NoOfUnits) != 0
)
SELECT startTime
       ,endTime
       ,SUM(NoOfUnits)
FROM summaryCTE  
group by startTime
         ,endTime  
OPTION (MAXRECURSION 0)

首先,当你的例子只显示了40个NoOfUnits时,单位数的总和怎么可能是160?我想你没有展示所有的东西,但这让我们找到了问题的症结所在。很多人都会因此而不愿意给你答案。如果您希望获得尽可能多的帮助,请包含一个工作脚本来创建一个虚拟表、预期输出和使您最接近预期结果的查询(但还不是很好:)+1,因为我相信您已经付出了很大的努力。作为SO上的新用户,欢迎。谢谢Lieven。我将看看是否可以编写一个脚本来生成一些虚拟数据。我已经编辑了关于数量的问题。@Lieven,是160,不是40。。。为了简洁起见,他省略了00:30和07:00之间的30分钟时段,即6.5小时(13个半小时时段)。我认为还有一个拼写错误……(以下半小时间隔有NoOfUnits=1)应该改为:(以下半小时间隔有NoOfUnits=10)。我不知道答案@DavidMaster84-你是对的,我的错误。谢谢你的时间Ed。我用一些示例数据补充了我的问题,这些数据涵盖了两天相同的日程数据。上面的代码生成了两个结果-两天13:00到00:00,单位数正确。但是,我只需要不同的时间和单位计数组,所以在这种情况下,我希望得到1个结果。@Daniel-请将您的预期结果添加到问题中好吗?我想我明白你想要什么,但如果能得到确认会很有帮助。感谢你的耐心Ed。我已将我的问题更改为包含用于生成数据的更新脚本,并包含了所需的结果。谢谢。@Daniel-我已经根据您提供的测试数据更新了我的答案,这太棒了。我对其他几个数据集运行了您的查询,它们都返回了正确的结果。非常感谢,谢谢阿斯坦德。我根据生成的测试数据运行了您的脚本(脚本已添加到原始问题中),它给出了我期望的结果。非常感谢。我将根据其他一些测试数据测试代码,例如,我的时间表每天都不同。知道我在答案中没有遗漏任何明显的东西(至少对我来说)是一种安慰——我本可以花上几个星期来解决这个问题,却没有接近你的解决方案!我刚刚在我的测试数据中添加了第三天的数据,其中每个HH插槽的单位计数为20,现在结果不正确-我在新的一天中每半小时得到一行,加上12:30到02:00之间所有单位的总和。你能给我们看一下这个新的测试数据吗,这样我就可以检查它了?此外,您希望按天分组,还是按具有值的每个连续条目分组?我需要查看分组为开始/结束时间(不考虑dat)和开始/结束时间总数量的唯一组合的数据。我将很快提供示例数据(现在必须破折号)。原始问题已更新,以更改数据创建脚本,并包括预期结果。
DECLARE @Table TABLE(
        DateVal DATETIME,
        NoOfUnits INT
)

INSERT INTO @Table SELECT '01 Mar 2010 00:30', 0

INSERT INTO @Table SELECT '01 Mar 2010 23:00', 10
INSERT INTO @Table SELECT '01 Mar 2010 23:30', 10
INSERT INTO @Table SELECT '02 Mar 2010 00:30', 10

INSERT INTO @Table SELECT '02 Mar 2010 01:00', 0

INSERT INTO @Table SELECT '02 Mar 2010 02:30', 20
INSERT INTO @Table SELECT '02 Mar 2010 03:30', 30
INSERT INTO @Table SELECT '02 Mar 2010 04:30', 40

INSERT INTO @Table SELECT '02 Mar 2010 05:00', 0

SELECT  *
FROM    @Table

;WITH DateValues AS(
        SELECT  t.DateVal,
                t.NoOfUnits,
                MIN(tNext.DateVal) MinDate
        FROM    @Table t LEFT JOIN
                @Table tNext    ON  t.DateVal < tNext.DateVal
                                AND tNext.NoOfUnits = 0
        WHERE   t.NoOfUnits != 0
        GROUP BY t.DateVal,
                t.NoOfUnits
)
, DateRanges AS(
        SELECT  DateVal StartDate,
                NoOfUnits,

            ISNULL((SELECT MAX(DateVal) FROM @Table WHERE DateVal < MinDate), (SELECT MAX(DateVal) FROM @Table)) EndDateEndDate
        FROM    DateValues
)
SELECT  MIN(StartDate) StartDate,
        SUM(NoOfUnits) TotalUnits,
        EndDate
FROM    DateRanges
GROUP BY EndDate
StartDate               TotalUnits  EndDate
----------------------- ----------- -----------------------
2010-03-01 23:00:00.000 30          2010-03-02 00:30:00.000
2010-03-02 02:30:00.000 90          2010-03-02 04:30:00.000
;WITH dateCTE
AS
(
        SELECT * 
               ,date + [time] dt
        FROM #Schedule
)
,seqCTE
AS
(
        SELECT NoOfUnits
               ,dt
               ,ROW_NUMBER() OVER (ORDER BY dt) AS rn
        FROM dateCTE               
)
,recCTE
AS
(
        SELECT NoOfUnits
               ,dt
               ,1 AS SEQUENCE
               ,rn
        FROM seqCTE
        WHERE rn = 1

        UNION ALL

        SELECT s.NoOfUnits
              ,s.dt
              ,CASE WHEN (s.NoOfUnits      > 0 
                          AND  r.NoOfUnits > 0
                         )
                      OR (s.NoOfUnits      = 0 
                          AND  r.NoOfUnits = 0
                         )
                    THEN r.SEQUENCE
                    ELSE r.SEQUENCE + 1
               END
              ,s.rn
        FROM recCTE AS r
        JOIN seqCTE AS s
        ON   s.rn = r.rn + 1
)
,summaryCTE
AS
(
        SELECT RIGHT(CONVERT(varchar(23),MIN(dt),120),8)  AS startTime
               ,RIGHT(CONVERT(varchar(23),MAX(dt),120),8) AS endTime
               ,SUM(NoOfUnits) AS NoOfUnits
        FROM recCTE
        GROUP BY SEQUENCE
        HAVING SUM(NoOfUnits) != 0
)
SELECT startTime
       ,endTime
       ,SUM(NoOfUnits)
FROM summaryCTE  
group by startTime
         ,endTime  
OPTION (MAXRECURSION 0)