我有一个棘手的问题让我头疼了一会儿。我有一些数据代表在可变天数内传递“小部件”,分为半小时插槽。
例如(格式化道歉 - 还没有完全掌握它):
Date Time NoOfUnits
01-Mar-2010 00:00 0
01-Mar-2010 00:30 0
01-Mar-2010 01:00 0
.... (following half hour intervals have NoOfUnits = 0)
01-Mar-2010 23:00 10
01-Mar-2010 23:30 10
02-Mar-2010 00:00 10
.... (following half hour intervals have NoOfUnits = 1)
02-Mar-2010 07:00 10
02-Mar-2010 07:30 0
.... (following half hour intervals have NoOfUnits = 0)
02-Mar-2010 23:30 0
我需要生成一个查询,允许我将这些数据分组到我提供单元的所有不同块中。在上面的示例中,我需要仅识别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
预期结果(尽管测试数据应从00:00开始,然后转到23:00而不是00:30到00:00):
StartTime TotalUnits EndDate
----------------------- ----------- -----------------------
1900-01-01 00:30:00.000 90 1900-01-01 04:30:00.000
1900-01-01 12:30:00.000 960 1900-01-02 00:00:00.000
答案 0 :(得分:3)
根据您提供的数据,这应该有效。它几乎可以肯定地被简化:
;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)
答案 1 :(得分:1)
如果我理解正确,请看一下这个例子。如果您有更多问题,请与我们联系。
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