2015-09-21 48 views
1

我有一個databasetable是以下形式的一行:分離行成幾個與SQL語句

ID | Amount | From  | To 
5 | 5439 | 01.01.2014 | 05.01.2014 

我想用SQL/T-SQL分裂這個長達一排PR月:

Amount | From  
5439 | 01.01.2014 
5439 | 02.01.2014 
5439 | 03.01.2014 
5439 | 04.01.2014 
5439 | 05.01.2014 

不幸的是,我不能更改數據庫源,我希望在SQL中這樣做,因爲我試圖將此查詢的結果與Powerpivot中的其他表進行比較。

編輯:在我的代碼的請求,我曾嘗試以下:

declare @counter int 
set @counter = 0 
WHILE @counter < 6 
begin 
    set @counter = @counter +1 
    select amount, DATEADD(month, @counter, [From]) as Dato 
    FROM [database].[dbo].[table] 
end 

然而,這返回幾個databasesets。

+3

我想你需要一個幫助日曆表在這裏加入。 – jarlh

+3

你的代碼在哪裏!你到目前爲止嘗試過什麼? – Marusyk

+0

您是否嘗試過遞歸查詢? https://technet.microsoft.com/en-us/library/ms186243(v=sql.105).aspx –

回答

4

您可以使用tally table生成所有日期。

SQL Fiddle

;WITH E1(N) AS(
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL 
    SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 
), 
E2(N) AS(SELECT 1 FROM E1 a CROSS JOIN E1 b), 
E4(N) AS(SELECT 1 FROM E2 a CROSS JOIN E2 b), 
Tally(N) AS(
    SELECT TOP(SELECT MAX(DATEDIFF(DAY, [From], [To])) + 1 FROM yourTable) 
     ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) 
    FROM E4 
) 
SELECT 
    yt.Id, 
    yt.Amount, 
    [From] = DATEADD(DAY, N-1, yt.[From]) 
FROM yourTable yt 
CROSS JOIN Tally t 
WHERE 
    DATEADD(DAY, N-1, yt.[From]) <= yt.[To] 

Simplified explanation on Tally Table

2

你需要 「流水號」 理貨表。這可能是一個函數(我在這裏簡單地發佈了一個:https://stackoverflow.com/a/32096945/5089204)或一個物理表(我在這裏發佈了一個示例:https://stackoverflow.com/a/32474751/5089204)或CTE以「即時」的方式執行此操作(表格示例是這樣做的)。

如果與發佈功能去也可能是這樣的:

declare @startDate DATETIME={d'2015-09-01'}; 
declare @EndDate DATETIME={d'2015-09-10'}; 
select DATEADD(DAY, Nmbr,@startDate) 
from dbo.GetRunningNumbers(DATEDIFF(DAY,@startDate,@endDate)+1,0); 
2
select * INTO #TEMP1 from 
(values 
(5 , 5439 , '01.01.2014', '05.01.2014'))t(id,amount,fromd,tod) 

WITH CTE 
AS 
(
    SELECT CAST(FROMD AS DATE) AS FROMD,amount,1 AS RN,ID FROM #TEMP1 
    UNION ALL 
    SELECT DATEADD(M,1,C.FROMD),C.amount,C.RN+1,C.ID 
    FROM CTE C 
      INNER JOIN #TEMP1 T ON T.id = C.ID AND DATEADD(M,1,c.FROMD)<=T.tod 

) 

SELECT * FROM CTE 
2
create table t (fd date, td date) 
insert into t values ('2015-01-01','2015-01-05') 

WITH DATES (fd, td, Level) 
AS 
(
    SELECT fd, td, 0 AS Level 
    FROM t 
    UNION ALL 
-- Recursive member definition 
    SELECT DATEADD(day,level+1,e.fd),e.td,Level + 1 
    FROM t AS e 
    INNER JOIN Dates AS d ON DATEADD(day,-d.level,d.fd) = e.fd AND d.fd < d.td 

) 
-- Statement that executes the CTE 
SELECT fd,td,level 
from DATES 
1

變種使用遞歸CTE

--variable table for data sample 
DECLARE @tbl AS TABLE 
    (
     ID INT , 
     Amount FLOAT , 
     [From] DATE , 
     [To] DATE 
    ) 
INSERT INTO @tbl 
     (ID, Amount, [From], [To]) 
VALUES (5, 5439, '2014-01-01', '2014-01-05') 

--final query using recursive cte 
; 
WITH cte 
      AS (SELECT T.ID , 
         T.Amount , 
         T.[From] , 
         T.[To] , 
         CONVERT(DATE, NULL) AS Dt , 
         n = 0 
       FROM  @tbl AS T 
       UNION ALL 
       SELECT cte.ID , 
         cte.Amount , 
         cte.[From] , 
         cte.[To] , 
         DATEADD(DAY, n, cte.[From]) , 
         cte.n + 1 
       FROM  cte 
       WHERE n <= DATEDIFF(day, cte.[From], cte.[To]) 
      ) 
    SELECT cte.ID , 
      cte.Amount , 
      dt AS [From] 
    FROM cte 
    WHERE cte.Dt IS NOT NULL 


SQL Fiddle