Jon*_*Red 6 sql t-sql sql-server-2005 gaps-and-islands
I have a table of data that looks a bit like this:
Name StartTime FinishTime Work
Bob 2010-08-03 08:00:00 2010-08-03 12:00:00 4
Bob 2010-08-03 13:00:00 2010-08-03 16:00:00 3
Pete 2010-08-04 08:00:00 2010-08-04 12:00:00 4
Mark 2010-08-04 10:00:00 2010-08-04 12:00:00 2
Run Code Online (Sandbox Code Playgroud)
None of these date ranges should ever span over midnight.
I want to write SQL that will give me the following output, given an input Start Date of 2010-08-02 and a Finish Date of 2010-08-05
Date Name TotalWork
2010-08-03 Bob 7
2010-08-03 Pete 3
2010-08-04 Pete 4
2010-08-04 Mark 2
Run Code Online (Sandbox Code Playgroud)
I could live with, and in fact may ultimately need, to have any days that do not have work associated also be represented in the results set, maybe as a row like this:
2010-08-05 NULL 0
Run Code Online (Sandbox Code Playgroud)
我不太确定如何以与使用其他语言相同的方式迭代SQL中的日期.
为了给出这个上下文,它的输出最终会插入Stacked Chart .Net控件.
有人可以给我一个线索,教程链接或其他一些帮助吗?否则我想我会在这几天摆弄这个!
谢谢!
乔纳森
试试这个:
Select DateAdd(day, 0, DateDiff(day, 0, StartDate)) Date,
Name, Sum (Work) TotalWork
From TableData
Group By Name, DateAdd(day, 0, DateDiff(day, 0, StartDate))
Run Code Online (Sandbox Code Playgroud)
让失踪的日子变得更难.
Declare @SD DateTime, @ED DateTime -- StartDate and EndDate variables
Select @SD = DateAdd(day, 0, DateDiff(day, 0, Min(StartDate))),
@ED = DateAdd(day, 0, DateDiff(day, 0, Max(StartDate)))
From TableData
Declare @Ds Table (aDate SmallDateTime)
While @SD <= @ED Begin
Insert @Ds(aDate ) Values @SD
Set @SD = @SD + 1
End
-- ----------------------------------------------------
Select DateAdd(day, 0, DateDiff(day, 0, td.StartDate)) Date,
td.Name, Sum (td.Work) TotalWork
From @Ds ds Left Join TableData td
On DateAdd(day, 0, DateDiff(day, 0, tD.StartDate)) = ds.aDate
Group By Name, DateAdd(day, 0, DateDiff(day, 0, tD.StartDate))
Run Code Online (Sandbox Code Playgroud)
编辑,我正在重新审视使用公用表表达式(CTE)的解决方案.这不需要使用日期表.
Declare @SD DateTime, @ED DateTime
Declare @count integer = datediff(day, @SD, @ED)
With Ints(i) As
(Select 0 Union All
Select i + 1 From Ints
Where i < @count )
Select DateAdd(day, 0, DateDiff(day, 0, td.StartDate)) Date,
td.Name, Sum (td.Work) TotalWork
From Ints i
Left Join TableData d
On DateDiff(day, @SD, d.StartDate) = i.i
Group By d.Name, DateAdd(day, 0, DateDiff(day, 0, d.StartDate))
Run Code Online (Sandbox Code Playgroud)
在SQL中迭代遍历行的方式是您不这样做.SQL是一种基于集合的语言,需要与其他过程语言完全不同的思维方式.如果你打算使用SQL,你真的需要能够在思考成功的过程中做出这样的转变.
这是我如何处理这个:
SELECT
CONVERT(VARCHAR(10), StartTime, 121) AS [date],
name,
SUM(work)
FROM
My_Table
WHERE
StartTime >= @start_date AND
StartTime < DATEADD(dy, 1, @finish_date)
GROUP BY
CONVERT(VARCHAR(10), StartTime, 121),
name
Run Code Online (Sandbox Code Playgroud)
此外,您的表设计看起来违反了正常的数据库设计标准.您的"工作"列实际上只是StartTime和FinishTime之间的计算.这使得它成为相同数据的重复,这可能导致各种各样的问题.例如,当你的StartTime和FinishTime相隔4个小时,你做什么,但"工作"说5个小时?
要包含没有相关工作的日期,您需要在前端处理,或者您需要一个"日历"表.它会包含所有日期,你可以用你的桌子进行LEFT JOIN.例如:
SELECT
CONVERT(VARCHAR(10), C.StartTime, 121) AS [date],
MT.name,
SUM(MT.work)
FROM
Calendar C
LEFT JOIN My_Table MT ON
MT.StartDate BETWEEN C.StartTime and C.FinishTime
WHERE
C.StartTime >= @start_date AND
C.StartTime < DATEADD(dy, 1, @finish_date)
GROUP BY
CONVERT(VARCHAR(10), C.StartTime, 121),
MT.name
Run Code Online (Sandbox Code Playgroud)
日历表还允许您向日期添加其他信息,例如假日标志,"加班"日(可能是星期日的工作时间等),等等.
注意:Charles Bretana的解决方案可能有点清晰,因为它将数据类型保留为日期时间而不是将它们转换为字符串.对于其他一些评论我会留在这里.
| 归档时间: |
|
| 查看次数: |
8414 次 |
| 最近记录: |