如何获得日期之间的计数并将行数写入 table 和 T-SQL?
How to get a count between to dates and write the count of rows into a table with T-SQL?
我的语言是 T-SQL,我正在使用 MS SQLServer 2008。
好吧,我有一个 table,里面有很多关于员工的信息数据。
每个员工都有一个"startdate"(他开始为公司工作的时间)和"enddate"(他辞职的时间)。
我想在 table 中写入与该员工在一个月内为公司工作的行数相同的行数。例如:
我的基础table:
员工编号 |开始日期 |结束日期
4711 20150101 20150523
此示例显示员工为公司工作了 5 个月。
所以我想在新的 table 5 行中插入以下信息:
新 Table:
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
希望你明白了,我尽量说得具体一些。
我认为您的选择是正确的。
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)
找到了您的新问题并想向您展示另一种方式:
您需要 运行 个号码的列表。在这个例子中,我首先创建了一个非常漂亮的函数。在许多情况下,您肯定会需要它...
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 一次性解决。由于每一行都有不同的间隔,因此您需要基于行的方法而不是基于集合的方法(什么是 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;
我的语言是 T-SQL,我正在使用 MS SQLServer 2008。
好吧,我有一个 table,里面有很多关于员工的信息数据。 每个员工都有一个"startdate"(他开始为公司工作的时间)和"enddate"(他辞职的时间)。 我想在 table 中写入与该员工在一个月内为公司工作的行数相同的行数。例如:
我的基础table:
员工编号 |开始日期 |结束日期 4711 20150101 20150523
此示例显示员工为公司工作了 5 个月。 所以我想在新的 table 5 行中插入以下信息:
新 Table:
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
希望你明白了,我尽量说得具体一些。
我认为您的选择是正确的。
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)
找到了您的新问题并想向您展示另一种方式:
您需要 运行 个号码的列表。在这个例子中,我首先创建了一个非常漂亮的函数。在许多情况下,您肯定会需要它...
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 一次性解决。由于每一行都有不同的间隔,因此您需要基于行的方法而不是基于集合的方法(什么是 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;