输入表
Start time End Time
8/12/14 17:00 8/14/14 12:00
我需要将输出显示如下
Date 11:00 to 23:00 23:00 to 11:00
8/12/14 6 1
8/13/14 12 12
8/14/14 1 11
我知道你们都会说“你们尝试了什么?”
但答案是“我想不出从哪里开始”
答案 0 :(得分:1)
使用递归CTE:
MS SQL Server 2012架构设置:
查询1 :
DECLARE @StartDate DateTime = '2014-08-12 17:00'
DECLARE @EndDate DateTime = '2014-08-14 12:00'
;WITH CTE
AS
(
SELECT @StartDate AS [Date],
CAST(@StartDate As time) AS [Time]
UNION ALL
SELECT DATEADD(HH, 1, [Date]) As [Date],
CAST(DATEADD(HH, 1, [Date]) AS Time) AS [Time]
FROM CTE
WHERE DATEADD(HH, 1, [Date]) < @EndDate
)
SELECT CAST([Date] AS Date) [Date],
SUM(CASE WHEN [Time] BETWEEN '11:00' AND '22:59'
THEN 1 ELSE 0 END) as [11:00 to 23:00],
SUM(CASE WHEN [Time] BETWEEN '00:00' AND '10:59'
THEN 1
WHEN [Time] Between '23:00' and '23:59' THEN 1
ELSE 0 END) as [23:00 to 11:00]
FROM CTE
GROUP BY CAST([Date] AS Date)
ORDER BY [Date]
<强> Results 强>:
| DATE | 11:00 TO 23:00 | 23:00 TO 11:00 |
|------------|----------------|----------------|
| 2014-08-12 | 6 | 1 |
| 2014-08-13 | 12 | 12 |
| 2014-08-14 | 1 | 11 |
答案 1 :(得分:1)
以下显示了使用Tally表(又名“数字表”表)的一种方法。
我做的主要假设:
我进一步假设数据存储在多个实体的表中 - 也就是说,您最终希望在一个查询中处理多个项目。如果你只想一次为一个项目做这件事,(a)下面的查询可以很容易地删除,(b)用C#或者任何调用语言可能更容易。
设置测试数据:
-- DROP TABLE Testing
CREATE TABLE Testing
(
EntryId int not null
,StartTime smalldatetime not null
,EndTime smalldatetime not null
)
INSERT Testing values
(1, 'Aug 12, 2014 17:00', 'Aug 14, 2014 12:00') -- Original problem
,(2, 'Aug 11, 2014 00:00', 'Aug 11, 2014 23:00') -- 23 hours
,(3, 'Aug 11, 2014 00:00', 'Aug 12, 2014 00:00') -- 24 hour shift
,(4, 'Aug 11, 2014 12:00', 'Aug 12, 2014 12:00') -- Noon to Noon
,(11, 'Aug 22, 2014 4:00', 'Aug 22, 2014 5:00') -- One-hour problem cases
,(12, 'Aug 22, 2014 10:00', 'Aug 22, 2014 11:00') -- One-hour problem cases
,(13, 'Aug 22, 2014 11:00', 'Aug 22, 2014 12:00') -- One-hour problem cases
,(14, 'Aug 22, 2014 12:00', 'Aug 22, 2014 13:00') -- One-hour problem cases
,(21, 'Aug 23, 2014 18:00', 'Aug 23, 2014 19:00') -- One-hour problem cases
,(22, 'Aug 23, 2014 22:00', 'Aug 23, 2014 23:00') -- One-hour problem cases
,(23, 'Aug 23, 2014 23:00', 'Aug 24, 2014 00:00') -- One-hour problem cases
,(24, 'Aug 24, 2014 00:00', 'Aug 24, 2014 1:00') -- One-hour problem cases
我的日常工作:
DECLARE
@Earliest smalldatetime
,@Latest smalldatetime
-- This could be thrown in as a first CTE, but doing so would make the overall query that much less comprehensible.
SELECT
@Earliest = min(StartTime)
,@Latest = max(EndTime)
from Testing
--where <filtering criteria, if you're not parsing the whole table)
;WITH
Pass0 as (select 1 as C union all select 1), --2 rows
Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows
Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows
Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows
Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows
Tally as (select row_number() over(order by C) as Number from Pass4),
DateRange as (select
dateadd(hh, ta.Number, @Earliest) ShiftHour
from Tally ta
where dateadd(hh, ta.Number, @Earliest) <= @Latest)
SELECT
te.EntryId
,cast(dateadd(hh, -1, dr.Shifthour) as date) [Date]
,sum(case when datepart(hh, dateadd(hh, -1, dr.Shifthour)) between 11 and 22 then 1 else 0 end) [11:00 to 23:00]
,sum(case when datepart(hh, dateadd(hh, -1, dr.Shifthour)) between 11 and 22 then 0 else 1 end) [23:00 to 11:00]
from Testing te
inner join DateRange dr
on dr.ShiftHour > te.StartTime
and dr.ShiftHour <= te.Endtime
group by
te.EntryId
,cast(dateadd(hh, -1, dr.Shifthour) as date)
order by
te.EntryId
,cast(dateadd(hh, -1, dr.Shifthour) as date)
将其插入以显示没有分组的结果,这对于弄清楚那里发生了什么是非常宝贵的:
;WITH
Pass0 as (select 1 as C union all select 1), --2 rows
Pass1 as (select 1 as C from Pass0 as A, Pass0 as B),--4 rows
Pass2 as (select 1 as C from Pass1 as A, Pass1 as B),--16 rows
Pass3 as (select 1 as C from Pass2 as A, Pass2 as B),--256 rows
Pass4 as (select 1 as C from Pass3 as A, Pass3 as B),--65536 rows
Tally as (select row_number() over(order by C) as Number from Pass4),
DateRange as (select
dateadd(hh, ta.Number, @Earliest) ShiftHour
from Tally ta
where dateadd(hh, ta.Number, @Earliest) <= @Latest)
SELECT
te.EntryId
,dateadd(hh, -1, dr.Shifthour)
,cast(dateadd(hh, -1, dr.Shifthour) as date) [Date]
,datepart(hh, dateadd(hh, -1, dr.Shifthour))
from Testing te
inner join DateRange dr
on dr.ShiftHour > te.StartTime
and dr.ShiftHour <= te.Endtime
order by
te.EntryId
,cast(dateadd(hh, -1, dr.Shifthour) as date)
,dateadd(hh, -1, dr.Shifthour)
困难的部分是:
<
和>
逻辑是的,这可能是过度工程,但有时你只需要试一试。我不能说它在大型数据集上的表现如何,如果你的第一个和最后一个日期超过四年,你需要在构建计数表时添加“Pass5”。
答案 2 :(得分:0)
DECLARE @StartTime DATETIME='08/01/2013 00:00:00'
,@EndTime DATETIME='08/03/2013 23:00:00'
DECLARE @StartDate DATE,
@Starthour INT,
@Startmin INT,
@EndDate DATE,
@Endhour INT,
@Endmin INT
SELECT @StartDate=CONVERT(DATE,@StartTime,101),@Starthour=DATEPART(HOUR,@StartTime),@Startmin=DATEPART(MINUTE,@StartTime)
SELECT @EndDate=CONVERT(DATE,@EndTime,101),@Endhour=DATEPART(HOUR,@EndTime),@Endmin=DATEPART(MINUTE,@EndTime)
DECLARE @T TABLE (StartTime DATETIME, EndTime DATETIME)
INSERT @T VALUES (DATEADD(MINUTE,-@Startmin,@StartTime), DATEADD(MINUTE,-@Endmin,@EndTime))
DECLARE @Final1 TABLE (ShiftDate DATETIME,[11:00 to 23:00] INT,[23:00 to 11:00] INT)
DECLARE @Final2 TABLE (ShiftDate DATETIME,[11:00 to 23:00] INT,[23:00 to 11:00] INT)
DECLARE @Final3 TABLE (ShiftDate DATETIME,[11:00 to 23:00] INT,[23:00 to 11:00] INT)
;WITH CTE AS
(
SELECT StartTime AS dt, EndTime,StartTime
FROM @T
UNION ALL
SELECT DATEADD(MINUTE, 60, dt) AS dt, EndTime,DATEADD(MINUTE, 60,StartTime) AS StartTime
FROM CTE
WHERE dt < DATEADD(HOUR, -1, EndTime)
)
INSERT INTO @Final1([11:00 to 23:00],[23:00 to 11:00],ShiftDate)
SELECT
CASE
WHEN CAST(dt AS TIME) >= '11:00' AND CAST(dt AS TIME) < '23:00' THEN 1
ELSE 0
END AS '11:00 to 23:00',
CASE
WHEN CAST(dt AS TIME) >= '11:00' AND CAST(dt AS TIME) < '23:00' THEN 0
ELSE 1
END AS '23:00 to 11:00'
,StartTime
FROM CTE
INSERT INTO @Final2([11:00 to 23:00],[23:00 to 11:00],ShiftDate)
SELECT SUM([11:00 to 23:00])*60 AS [11:00 to 23:00]
,SUM([23:00 to 11:00])*60 AS [23:00 to 11:00]
,CONVERT(DATE,DATEADD(MINUTE,-660,ShiftDate)) AS ShiftDate
FROM @Final1
GROUP BY CONVERT(DATE,DATEADD(MINUTE,-660,ShiftDate))
INSERT INTO @Final3([11:00 to 23:00],[23:00 to 11:00],ShiftDate)
SELECT CASE WHEN ShiftDate=@StartDate AND @Starthour BETWEEN 11 AND 22 THEN [11:00 to 23:00]-@Startmin ELSE [11:00 to 23:00] END AS [11:00 to 23:00],
CASE WHEN ShiftDate=@StartDate AND @Starthour BETWEEN 23 AND 10 THEN [23:00 to 11:00]-@Startmin ELSE [23:00 to 11:00] END AS [23:00 to 11:00],
ShiftDate
FROM @Final2
SELECT ShiftDate,
CONVERT(VARCHAR(10),
(CASE WHEN ShiftDate=@EndDate AND @Endhour BETWEEN 11 AND 22
THEN [11:00 to 23:00]+@Endmin
ELSE [11:00 to 23:00] END)) AS [11:00 to 23:00],
CONVERT(VARCHAR(10),
(CASE WHEN ShiftDate=@EndDate AND @Endhour BETWEEN 23 AND 10
THEN [23:00 to 11:00]+@Endmin
ELSE [23:00 to 11:00] END)) AS [23:00 to 11:00]
FROM @Final3