如何获取日期之间的计数并使用T-SQL将行数写入表中?

时间:2015-09-23 08:11:24

标签: sql-server tsql date cursor

我的语言是T-SQL,我正在使用MS SQLServer 2008。

好吧,我有一张包含大量数据的表格,其中包含有关员工的信息。 每个员工都有一个“startdate”(他开始为公司工作的时间)和“enddate”(他退出工作的时间)。 我想在一个表中写入与员工在一个月内为公司工作的行数相同的行数。例如:

我的基本表:

员工编号| StartDate |结束日期 4711 20150101 20150523

此示例显示该员工为公司工作了5个月。 所以我想在新表中插入5行,其中包含以下信息:

新表:

  Employee Number | StartDate | EndDate
  row1: 4711               20150101   20150523

  row2: 4711               20150201   20150523

  row3: 4711               20150301   20150523

  row4: 4711               20150401   20150523

  row5: 4711               20150501   20150523

我试过这个来获取日期之间的月份数。我想我需要使用光标或类似的东西。

    declare @start DATE = '2011-05-01'
declare @end DATE = '2011-08-01'

;with months (date)
AS
(
    SELECT @start
    UNION ALL
    SELECT DATEADD(month,1,date)
    from months
    where DATEADD(month,1,date)<=@end
)
select Datename(month,date) from months

希望你明白这一点,我尽力做到最具体。

2 个答案:

答案 0 :(得分:3)

我认为你走的是正确的道路。

declare @start DATE = (select min(startdate) from dbo.employee)
declare @end DATE = cast(sysdatetime() as date)

set @start = DATEADD(day, - datepart(day, @start) + 1, @start)

;with months (date)
AS
(
    SELECT @start
    UNION ALL
    SELECT DATEADD(month,1,date)
    from months
    where DATEADD(month,1,date)<=@end
)
select employee.EmployeeNumber, Year = datepart(year, date), Month = DATENAME(month, date), employee.StartDate, employee.EndDate
from months
inner join dbo.employee on month.date >= employee.startdate and (month.date <= employee.enddate or employee.enddate is null)

答案 1 :(得分:1)

找到了您的新问题,并希望以另一种方式向您展示:

您需要一个正在运行的号码列表。在这个例子中,我首先创建一个非常漂亮的函数。在许多场景中你肯定会需要这个......

CREATE FUNCTION [dbo].[GetRunningNumbers](@counter INT=10000000, @StartAt INT=0)
RETURNS TABLE
AS 
RETURN
WITH E1(N) AS( -- 10 ^ 1 = 10 rows
    SELECT 1 FROM(VALUES (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))t(N)
),
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), -- 10 ^ 2 = 100 rows
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), -- 10 ^ 4 = 10,000 rows
E8(N) AS(SELECT 1 FROM E4 a CROSS JOIN E4 b), -- 10 ^ 8 = 10,000,000 rows
CteTally AS(
    SELECT TOP(ISNULL(@counter,1000000)) ROW_NUMBER() OVER(ORDER BY(SELECT NULL)) -1 + ISNULL(@StartAt,0) As Nmbr
    FROM E8
)
SELECT * FROM CteTally;
GO

您的问题以CROSS APPLY为单行解决。由于每行中有不同的intervalls,因此需要基于行的方法而不是基于集合(CTE是什么)。

DECLARE @tbl TABLE(id INT, someValue VARCHAR(10),StartDate DATETIME, EndDate DATETIME);
INSERT INTO @tbl VALUES(1,'test1',{d'2015-01-04'},{d'2015-01-06'})
                      ,(2,'test2',{d'2015-01-02'},{d'2015-01-08'}) --overlapping
                      ,(3,'test3',{d'2015-01-10'},{d'2015-01-13'});
SELECT *
      ,DATEADD(DAY,RuNmbr.Nmbr,StartDate) AS RunningDate
FROM @tbl AS tbl
CROSS APPLY dbo.GetRunningNumbers(DATEDIFF(DAY,StartDate,EndDate)+1,0) AS RuNmbr;