我的语言是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
希望你明白这一点,我尽力做到最具体。
答案 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;