Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/xamarin/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server T-SQL:在datediff中为每天创建记录_Sql Server_Tsql - Fatal编程技术网

Sql server T-SQL:在datediff中为每天创建记录

Sql server T-SQL:在datediff中为每天创建记录,sql-server,tsql,Sql Server,Tsql,我的表格结构如下: EmployeeID, StartDate, EndDate, Hours --------------------------------------- 1 1/1/2016 1/8/2016 20 2 1/4/2016 1/6/2016 10 3 1/2/2016 1/3/2016 13 我需要将小时除以开始日期和结束日期的datediff,并显示每天的记录,如下所示: 1 1/

我的表格结构如下:

EmployeeID, StartDate, EndDate, Hours
---------------------------------------
1           1/1/2016   1/8/2016 20
2           1/4/2016   1/6/2016 10
3           1/2/2016   1/3/2016 13
我需要将小时除以开始日期和结束日期的datediff,并显示每天的记录,如下所示:

1           1/1/2016   1/2/2016 2.85
1           1/2/2016   1/3/2016 2.85
...
1           1/7/2016   1/8/2016 2.85
2           1/4/2016   1/5/2016 5
2           1/5/2016   1/6/2016 5
3           1/2/2016   1/3/2016 13   
小时数应四舍五入至小数点后两位。假设开始日期和结束日期从不相同

如何使用T-SQL实现这一点

编辑:我不是SQL专家,所以我没有做过很多尝试,因为它看起来不像一个简单的选择。我想我需要使用“分区依据”?就小时数而言,2.86也可以。向上取整或向下取整并不重要,只要是一致的

另外,为了澄清,我不需要3行。我需要10排。我不只是需要一个简单的

hours / datediff(day, startdate, enddate)
您必须为此使用理货表:

;WITH Tally AS (
   SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) AS n
   FROM (VALUES (0), (0), (0), (0), (0), (0)) t1(v)
   CROSS JOIN (VALUES (0), (0), (0), (0), (0), (0)) t2(v)
)
SELECT t1.EmployeeID,
       DATEADD(d, t3.n-1, t1.StartDate), 
       DATEADD(d, t3.n, t1.StartDate), 
       ROUND([Hours] * 1.0 / t2.days, 2)
FROM mytable AS t1
CROSS APPLY (SELECT DATEDIFF(d, t1.StartDate, t1.EndDate)) As t2(days)
JOIN Tally AS t3 ON t3.n <= t2.days
ORDER BY t1.EmployeeID, n, t1.StartDate

上面的查询使用CTE创建一个包含36行的理货表。它可以很容易地扩展以创建更多的行。

通过加入数字列表可以取消该日期范围。 和master..spt_值可用于此

要将[hours]除以datediff,首先将其转换为浮点数,然后通过四舍五入将其截断为2位小数

选择t.EmployeeID, dateaddd,v.number,t.StartDate作为StartDate, dateaddd,v.number+1,t.StartDate作为结束日期, t、 将小时数改为[小时] 从…起 选择EmployeeID、StartDate、EndDate、, 按浮动/日期差分、开始日期、结束日期、2,1小时进行的圆形广播[小时] 从myTable 其中EndDate>StartDate T 加入主..spt_值v v.type='P'和v.number>=0和v.number
EmployeeID StartDate   EndDate     Hours
1          2016-07-01  2016-07-02  2,85
1          2016-07-02  2016-07-03  2,85
1          2016-07-03  2016-07-04  2,85
1          2016-07-04  2016-07-05  2,85
1          2016-07-05  2016-07-06  2,85
1          2016-07-06  2016-07-07  2,85
1          2016-07-07  2016-07-08  2,85
2          2016-07-04  2016-07-05  5
2          2016-07-05  2016-07-06  5
3          2016-07-02  2016-07-03  13
然而,只有当datediff低于2047时,这才有效。 因为2047是从系统表中获得的最大数量。 但这仍然是一个超过5年的日期范围

但是如果你在那张桌子上有更大的范围。 然后,您可以生成一个包含更多数字的表。 本例将1000000个数字放入表变量:

DECLARE @Numbers TABLE (num int primary key);

-- Who dares to claim that cross joins are always useless?
WITH d AS (select n from (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9))q(n))
insert into @Numbers (num)
select (d6.n*100000+d5.n*10000+d4.n*1000+d3.n*100+d2.n*10+d1.n) as num 
from d d1, d d2, d d3, d d4, d d5, d d6;

select count(*) as total, min(num) as min_num, max(num) as max_num from @Numbers;
您也可以使用递归来实现这一点。 但是如果您想添加额外的列,那么这种方法有点麻烦。 要从myTable中添加更多列,可以在EmployeeID中将myTable左键连接到R

WITH R (EmployeeID, StartDate, EndDate, FinalDate, [Hours]) AS
(
    SELECT EmployeeID, StartDate, dateadd(d, 1, StartDate),
    EndDate as FinalDate,
    round(cast([Hours] as float)/datediff(d, StartDate, EndDate),2,1)
    from myTable
    where StartDate < EndDate
    UNION ALL
    SELECT EmployeeID, dateadd(d, 1, StartDate), dateadd(d, 2, StartDate),
    FinalDate, [Hours]
    FROM R WHERE dateadd(d, 1, StartDate) < FinalDate
)
SELECT EmployeeID, StartDate, EndDate, [Hours]
FROM R
ORDER BY EmployeeID, StartDate, EndDate;
如果拆分的总小时数仍然需要等于原始小时数? 然后它变得稍微复杂一点

declare @myTable TABLE (EmployeeID int, StartDate date, EndDate date, [Hours] int);

insert into @myTable values 
(0,'2016-1-1','2016-1-4',10),
(1,'2016-1-1','2016-1-8',20);

WITH R (EmployeeID, StartDate, EndDate, FinalDate, [Hours], RemainingHours) AS
(
    SELECT EmployeeID, 
    StartDate, 
    dateadd(d, 1, StartDate),
    EndDate,
    round(cast([Hours] as float)/datediff(d, StartDate, EndDate),2,1),
    round(cast([Hours] as float),2,1)
    from @myTable
    where StartDate < EndDate
    UNION ALL
    SELECT EmployeeID, 
    dateadd(d, 1, StartDate),
    dateadd(d, 1, EndDate),
    FinalDate,
    (case when dateadd(d, 1, EndDate) < FinalDate then [Hours] else (RemainingHours - [Hours]) end),
    (RemainingHours - [Hours])
    FROM R WHERE EndDate < FinalDate
)
SELECT EmployeeID, StartDate, EndDate, [Hours]
FROM R
ORDER BY EmployeeID, StartDate, EndDate;

那么,你试过什么了?@clifton_h看我的编辑我用了你的第二个建议。工作起来很有魅力。谢谢。递归看起来像某种秘密的艺术。很高兴听到这有帮助:使用递归方法,我们将如何在最后一条记录上进行精度损失?所以,如果我们把10小时除以3天,我们每天得到3.33。最后一天,我想看3.34。这是一个有趣的小挑战我在答案中添加了一个解决方案。