将多个数据范围拆分为多行

时间:2016-11-16 15:22:57

标签: sql sql-server datetime split

这是我的问题:

我有一张桌子:

FIELD_1   FIELD_2   FIELD_N   StartDate     EndDate       OTHER_FIELDS
value1    value2    valuen    2016-01-12    2016-05-12    othervalues  
value3    value4    valuen    2015-01-12    2015-05-12    othervalues  

我需要在其他多行中拆分多行的数据范围。

如下:

StartDate                 EndDate                   other_columns
2016-01-12                2016-05-12                myvalues
2016-01-13                2016-05-12                myvalues
2016-01-14                2016-05-12                myvalues
..                        ..                        ..
..                        ..                        .. 
2015-01-12                2015-05-12                myvalues
2015-01-13                2015-05-12                myvalues
..                        ..                        ..

这是我的代码:

CREATE TABLE [dbo].[OUTPUT_TABLE](
    [STARTDATE] [datetime] NULL,
    [ENDDATE] [datetime] NULL,
    [OTHER_FIELDS] [nvarchar](30) NULL,
) ON [PRIMARY]

GO

DECLARE @cnt INT 
DECLARE @startDate DATETIME 
DECLARE @endDate DATETIME 
DECLARE @incr INT 
DECLARE @tempDate DATETIME 

SET @startDate=(SELECT [StartDate] 
                FROM   [dbo].[INPUT_TABLE]) 
SET @endDate=(SELECT [EndDate] 
               FROM   [dbo].[INPUT_TABLE]) 
SET @cnt=Datediff(dd, @startDate, @endDate) 
SET @incr=0 
SET @tempDate=Dateadd(dd, @incr, Cast(@startDate AS DATETIME)) 

WHILE @cnt >= 0   
  BEGIN 
      IF @cnt = 0 
        BEGIN 
            INSERT INTO  [dbo].[OUTPUT_TABLE]  
            VALUES     (@tempDate, 
                        @endDate, 
                        NULL 
                         ); 
        END 
      ELSE 
        BEGIN 
            INSERT INTO [dbo].[OUTPUT_TABLE]  
            VALUES     (@tempDate, 
                        Dateadd(dd, Datediff(dd, 0, @tempDate) + 1, -1), 
                        NULL 
                         ); 
        END 


      SET @tempDate=Dateadd(dd, @incr + 1, Dateadd(dd, Datediff(dd, 0, 
                                                       @startDate) 
                                           , 0)) 
      SET @cnt=@cnt - 1 
      SET @incr=@incr + 1 
  END 

目前代码在输入表上有一行的情况下工作,但考虑到我需要在多行上迭代它,我目前还没有找到解决方案。这里有人知道谁可以帮我解决这个问题?

非常感谢你提前, 亲切的问候, 路易

2 个答案:

答案 0 :(得分:1)

以下是如何利用计数表来简化此工作的方法。根本不需要循环。如果需要,您可以使用ctes动态创建计数表。在我的系统中,我有一个像这样定义的视图。

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

你真的应该对计数表非常熟悉。它被称为t-sql"的瑞士军刀。

现在我们需要表和数据来完成设置问题。

create table #InputTable
(
    SomeID int identity primary key
    , StartDate date
    , EndDate date
    , OTHER_FIELDS varchar(20)
)

insert #InputTable
(
    StartDate
    , EndDate
    , OTHER_FIELDS
)
select '2016-01-12', '2016-05-12', 'othervalues' union all
select '2015-01-12', '2015-05-12', 'othervalues'

CREATE TABLE [dbo].[OUTPUT_TABLE](
    [STARTDATE] [datetime] NULL,
    [ENDDATE] [datetime] NULL,
    ThisDate date,
    [OTHER_FIELDS] [nvarchar](30) NULL,
) ON [PRIMARY]

现在我们已经完成了整个问题,我们实际上可以开始研究解决方案了。利用计数表使这非常简单。只有一个插入语句。

insert OUTPUT_TABLE
(
    STARTDATE
    , ENDDATE
    , ThisDate
    , OTHER_FIELDS
)
select it.StartDate
    , it.EndDate
    , DATEADD(day, t.N - 1, it.StartDate)
    , it.OTHER_FIELDS
from #InputTable it
join cteTally t on t.N <= DATEDIFF(day, it.StartDate, it.EndDate) + 1

现在我们可以检查这是否真的像我们认为的那样有效。

select * 
from OUTPUT_TABLE

看那个。 243行,每个日期与基表中每个开始日期和结束日期的值之间的日期。没有循环,没有游标。剩下的只是一点清理,以消除我们的腿部工作的证据。

drop table OUTPUT_TABLE
drop table #InputTable

答案 1 :(得分:0)

也许创建一个包含日期的日历表,然后加入它。

SELECT *
FROM input_table it
JOIN calendar c on c.date >= it.startdate and c.date <= it.enddate