2010-08-31 48 views
6

迭代我有数据表,看起来有点像这样:通过日期在SQL

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 

这些日期范围都不应该永远跨越午夜。
我想要写SQL,这将使我下面的输出,给出2010-08-02和输入开始日期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 

一个完成日期,我可以住在一起,并在事实可能最终需要,有没有相关的还有在设定的结果表示工作的任何日子,也许是一排这样的:

2010-08-05  NULL 0 

我不太清楚如何通过SQL日期迭代就像我会用其他语言一样。

为了给这个上下文,这个输出将最终插入到Stacked Chart .Net控件中。

有人能给我一个线索,指向一个教程的链接或其他一些帮助吗?否则,我想我会摆弄这几天!

谢谢!

乔纳森

回答

7

试试这个:

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

要得到缺少的日子更难。

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

编辑,我与使用公用表表达式(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)) 
+0

啊...看起来非常好,谢谢。如果我想使用参数@SD和@ED,我会采取它,不管我是否想要失踪的日子,那么我必须构建临时表? – JonRed 2010-08-31 14:18:07

+0

@JonRed,如果你不想缺少日期,那么使用第一个SQL。在这种情况下,您不需要T-Sql变量或临时表。如果您需要缺少日期,那么您需要临时表,并且需要T-Sql变量来填充它。 – 2010-08-31 14:24:53

+0

真是好戏...... – Zafer 2010-08-31 14:29:13

5

您在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 

而且,你的表的设计看起来像它违反了正常的数据库设计标准。您的“工作”栏实际上只是StartTime和FinishTime之间的计算。这使得它成为相同数据的重复,这可能会导致各种问题。例如,当您的StartTime和FinishTime相隔4小时时,您会做什么,但“工作”说5小时?要包含没有关联的日期,您需要在前端处理该日期,否则您需要一个“日历”表。它会包含所有的日期,并且你会用你的表做一个左连接。例如:

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 

日历表还可以让你更多的信息添加到日期,如节假日的标志,“加班”天(也许计数工作时间和周日半),等等。

注意:查尔斯布雷塔纳的解决方案可能有点清洁,因为它保持数据类型为日期时间而不是将它们转换为字符串。尽管对于其他一些评论,我会在这里留下。

+0

你的意思是转换吗? – 2010-08-31 14:13:14

+0

工作不仅仅是两个日期之间的差异;这个表中没有记录%effort元素。为了简单起见,我将几个链接表格表示为一个表格。 感谢您的这一点。当我正在解决我的设计正在发生的问题时,您的意见非常有帮助。 – JonRed 2010-08-31 14:23:14

+1

@Charles - 不,COVERT是一种新的ANSI标准功能,当您需要绝密色谱柱时。 ;)感谢您的更正。 – 2010-08-31 14:37:16