Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.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-复制行并在两个日期值之间添加日期迭代器列_Sql_Sql Server_Tsql - Fatal编程技术网

SQL Server-复制行并在两个日期值之间添加日期迭代器列

SQL Server-复制行并在两个日期值之间添加日期迭代器列,sql,sql-server,tsql,Sql,Sql Server,Tsql,我有一个表,类型为varchar、varchar、date和date: NAME | ID | FROM | THRU Bob | A123 | 10/30/2010 | 11/2/2010 Bob | B567 | 10/30/2010 | 11/2/2010 我想添加一个服务日期DOS列,该列复制行,并在开始日期和结束日期之间(包括开始日期和结束日期)每天进行迭代。完成的表格应如下所示: NAME | ID | FROM | THRU | D

我有一个表,类型为varchar、varchar、date和date:

NAME | ID   | FROM       | THRU
Bob  | A123 | 10/30/2010 | 11/2/2010
Bob  | B567 | 10/30/2010 | 11/2/2010
我想添加一个服务日期DOS列,该列复制行,并在开始日期和结束日期之间(包括开始日期和结束日期)每天进行迭代。完成的表格应如下所示:

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中实现这一点呢?

听起来您需要一个解决方案。然后它就变得像这样简单:

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;

注意,我使用了我自己的日历表,没有与链接相同的列名,但是,链接提供了如何设计日历表所需的所有信息。您只需确保使用适合表的列名。

您可以将服务日期创建为计算列。要增加日期,可以尝试以下操作:

SELECT DATEADD(day, 1, '2017/08/25') AS DateAdd;

我认为日历表在这里不太合适。既然你想要连续的日期,理货台似乎是个不错的选择

首先,让我们设置您的数据

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

如果您没有强烈推荐的日历表,另一个选项是临时理货表

范例

返回


我经常使用递归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);
看来交叉申请就行了

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)
返回:


10/30不是datetime的有效值。datetime数据类型返回一个精确到1/300秒的值,不确定这是什么;月/日那么,哪一年?月/年那么哪一天??您拥有的真实值或真实数据类型是什么?如果您真的是以MM/dd格式存储日期,那么当您从一年到另一年时,这将是不可能的。@Larnu您是对的。我添加了一个年份值,以便更加清晰,并将datetime更改为date。这是日历表的一个很好的用例。日历表中的每个日期都有一行,它将包含所有日期。网上有很多关于如何快速创建的资源。一旦你有了这些,你就可以加入到你现有的表中,比如选择你的表。*,calendartable.calendardate FROM yourtable,其中calendartable.calendardate在yourtable.FROM和yourtable之间。这如何回答他们的问题?他们想要从开始到结束之间的每个日期。这如何生成额外的行?这样的表达式提供了一个额外的列,而不是额外的行。如果范围很小,这没什么大不了的,但是对于1000左右的大范围,这真的会陷入困境。递归CTE生成顺序值实际上是隐藏的RBAR@西兰格。问题是,当进入大范围时,联接也可能需要很长时间。在我看来,一个很好的起点是亚伦·伯特兰的测量。我的偏好是因为这是标准的SQL,不需要额外的表,并且适用于任意数量的值。我不认为这是执行最快的方法。在他的文章中,递归cte是他测试的第二个最慢的选项。我从未对标准的符合ANSI标准的sql给出过太多的信条。在我20年的商业生涯中,我为一个系统切换数据库的次数为零。即使发生了这种情况,也会有许多其他的事情需要发生。我在视图中使用递归cte技术,因此它不会存储在任何地方,而且速度非常快。看起来与我的非常相似+1@SeanLange苹果和桔子:你有一个加入,我有一个交叉申请。不过,我敢打赌你的表现会更好+1如果是,则可能无法在这个小数据集上检测到。唯一的性能差异是创建理货表。我们之间有4个或更多正确答案中的2个:@这是我们必须承担的负担。我的桌子有7.5亿多行。对于这么大的桌子,日历桌或理货桌会更快吗?可能没什么区别。无论哪种方式,您都要将7.5亿行连接到另一个表,以大大增加行数。
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);
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  |
+------+------+---------------------+---------------------+---------------------+