我有一个表,其类型为varchar,varchar,日期和日期:
NAME | ID | FROM | THRU
Bob | A123 | 10/30/2010 | 11/2/2010
Bob | B567 | 10/30/2010 | 11/2/2010
我想添加一个服务日期(DOS)列,该列复制行并针对FROM和THRU日期之间(包括该日期)的每一天进行迭代。成品表应如下所示:
NAME | ID | FROM | THRU | DOS
Bob | A123 | 10/30/2010 | 11/02/2010 | 10/30/2010
Bob | A123 | 10/30/2010 | 11/02/2010 | 10/31/2010
Bob | A123 | 10/30/2010 | 11/02/2010 | 11/01/2010
Bob | A123 | 10/30/2010 | 11/02/2010 | 11/02/2010
Bob | B567 | 10/30/2010 | 11/02/2010 | 10/30/2010
Bob | B567 | 10/30/2010 | 11/02/2010 | 10/31/2010
Bob | B567 | 10/30/2010 | 11/02/2010 | 11/01/2010
Bob | B567 | 10/30/2010 | 11/02/2010 | 11/02/2010
我看到了另一个使用cte但未保留原始日期值并添加DOS列的答案。如何在SQL Server中完成此操作?
答案 0 :(得分:3)
我认为日历表不是这里的正确工具。由于您想要连续的日期,理货表似乎是个不错的选择。
首先让我们设置您的数据。
declare @Something table
(
NAME varchar(10)
, ID varchar(10)
, DateFrom date
, THRU date
)
insert @Something values
('Bob', 'A123', '20101030', '20101102')
, ('Bob', 'B567', '20101030', '20101102')
接下来,我们需要统计表。我在系统上保留一个视图,读取速度为零,读取速度很快。可以根据您的需要随意调整行数。
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
现在,查询您的情况非常简单。
select s.Name
, s.ID
, s.DateFrom
, s.THRU
, DOS = DATEADD(day, t.N - 1, DateFrom)
from @Something s
join cteTally t on t.N <= datediff(day, DateFrom, THRU) + 1
order by s.Name
, s.ID
, t.N
答案 1 :(得分:2)
听起来像您需要Calendar table。然后它变得像这样简单:
SELECT YT.Name,
YT.ID,
YT.[From],
YT.Thru,
CT.CalendarDate AS DOS
FROM dbo.YourTable YT
JOIN dbo.CalendarTable CT ON CONVERT(date,YT.[From]) <= CT.CalendarDate
AND CONVERT(date,YT.Thru) >= CT.CalendarDate;
注意,我使用了自己的Calendar表,该链接没有相同的列(名称),但是,该链接提供了有关如何设计的所有信息。您只需要确保使用适合表的列名即可。
答案 2 :(得分:2)
如果您没有日历表(强烈建议使用),则另一个选择是临时计价表
示例
Select A.*
,DOS = B.D
From YourTable A
Cross Apply (
Select Top (DateDiff(DAY,[FROM],[THRU])+1) D=DateAdd(DAY,-1+Row_Number() Over (Order By (Select Null)),[FROM])
From master..spt_values n1,master..spt_values n2
) B
返回
NAME ID FROM THRU DOS
Bob A123 2010-10-30 2010-11-02 2010-10-30
Bob A123 2010-10-30 2010-11-02 2010-10-31
Bob A123 2010-10-30 2010-11-02 2010-11-01
Bob A123 2010-10-30 2010-11-02 2010-11-02
Bob B567 2010-10-30 2010-11-02 2010-10-30
Bob B567 2010-10-30 2010-11-02 2010-10-31
Bob B567 2010-10-30 2010-11-02 2010-11-01
Bob B567 2010-10-30 2010-11-02 2010-11-02
答案 3 :(得分:2)
对于这种事情,我经常使用递归CTE:
with cte as (
select t.ame, t.id, t.from, t.thru, t.from as dos
from t
union all
select cte.ame, cte.id, cte.from, cte.thur, dateadd(day, 1, dos)
from cte
where dos < t.thru
)
select cte.*
from cte
option (maxrecursion 0);
答案 4 :(得分:0)
您可以将服务日期创建为计算列。要增加日期,您可以尝试以下操作:
SELECT DATEADD(day, 1, '2017/08/25') AS DateAdd;
答案 5 :(得分:0)
似乎CROSS APPLY
会完成工作
CREATE TABLE T(
[NAME] varchar(3),
[ID] varchar(4),
[FROM] datetime,
[THRU] datetime
);
INSERT INTO T
([NAME], [ID], [FROM], [THRU])
VALUES
('Bob', 'A123', '2001-10-30 00:00:00', '2001-11-02 00:00:00'),
('Bob', 'B567', '2001-10-30 00:00:00', '2001-11-02 00:00:00');
SELECT T.*,
DATEADD(Day, TT.N, [FROM]) DOS
FROM T CROSS APPLY (VALUES (0), (1), (2), (3)) TT(N)
返回:
+------+------+---------------------+---------------------+---------------------+
| NAME | ID | FROM | THRU | DOS |
+------+------+---------------------+---------------------+---------------------+
| Bob | A123 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 30/10/2001 00:00:00 |
| Bob | A123 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 31/10/2001 00:00:00 |
| Bob | A123 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 01/11/2001 00:00:00 |
| Bob | A123 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 02/11/2001 00:00:00 |
| Bob | B567 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 30/10/2001 00:00:00 |
| Bob | B567 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 31/10/2001 00:00:00 |
| Bob | B567 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 01/11/2001 00:00:00 |
| Bob | B567 | 30/10/2001 00:00:00 | 02/11/2001 00:00:00 | 02/11/2001 00:00:0 |
+------+------+---------------------+---------------------+---------------------+