Reputation: 101
I have the following rows from a table in SQL Server 2008 R2
+-------------------------------------------+
| ID EntryType dt price |
+-------------------------------------------+
| 14 4 2012-11-07 0.025000 |
| 16 5 2012-11-07 0.026000 |
| 18 6 2012-11-07 0.026000 |
| 20 7 2012-11-07 0.026000 |
+-------------------------------------------+
What I would like to do is spread the rows based on the EntryType (the EntryType doesn't change)
For EntryType = 4 (1 row)
For EntryType = 5 (2 row)
For EntryType = 6 (3 row)
For EntryType = 7 (9 row)
and the dt field will be incremented (in a Month interval), so the output looks like this:
+-----------+-----------+-------+
| EntryType | dt | Price |
+-----------+-----------+-------+
| 4 | 11/7/2012 | 0.024 |
| 5 | 12/7/2012 | 0.025 |
| 5 | 1/7/2013 | 0.025 |
| 6 | 2/7/2013 | 0.026 |
| 6 | 3/7/2013 | 0.026 |
| 6 | 4/7/2013 | 0.026 |
| 7 | 5/7/2013 | 0.027 |
| 7 | 6/7/2013 | 0.027 |
| 7 | 7/7/2013 | 0.027 |
| 7 | 8/7/2013 | 0.027 |
| 7 | 9/7/2013 | 0.027 |
| 7 | 10/7/2013 | 0.027 |
| 7 | 11/7/2013 | 0.027 |
| 7 | 12/7/2013 | 0.027 |
| 7 | 1/7/2014 | 0.027 |
+-----------+-----------+-------+
Is it possible to do that with CTE and SQL?
Upvotes: 2
Views: 308
Reputation: 16904
;WITH e (ID, EntryType, row, dt, Price, [Len])
AS
(
SELECT ID, EntryType, CASE EntryType WHEN 4 THEN 1
WHEN 5 THEN 2
WHEN 6 THEN 3
WHEN 7 THEN 9 END AS row,
dt, Price, 0 AS [Len]
FROM dbo.your_table
), x (ID, EntryType, row, dt, Price, [Len]) AS
(
SELECT ID, EntryType, row, dt, Price, 1
FROM e
UNION ALL
SELECT e.ID, e.EntryType, e.row, e.dt, e.Price, x.[Len] + 1
FROM e , x
WHERE e.ID = x.ID AND e.row > x.[Len]
)
SELECT EntryType, DATEADD(mm, ROW_NUMBER() OVER(ORDER BY EntryType)-1, dt) AS dt, Price
FROM x
ORDER BY EntryType
Only thing I can't understand by what criteria to receive Price?
Demo on SQL Fiddle
Upvotes: 2
Reputation: 15251
Here is a way to do this in a recursive CTE:
;with RecordCounts as (
-- Establish row counts for each EntryType
select 4 as EntryType, 1 as RecordCount
union all select 5, 2
union all select 6, 3
union all select 7, 9
), PricesCte as (
-- Get initial set of records
select ID, p.EntryType, (select min(dt) from MyTable) as dt, price, 1 as RecordNum
from MyTable p
join RecordCounts c on p.EntryType = c.EntryType -- Only get rows where we've established a RecordCount
-- Add records recursively according to RecordCount
union all
select ID, p.EntryType, dt, price, RecordNum + 1
from PricesCte p
join RecordCounts c on p.EntryType = c.EntryType
where RecordNum + 1 <= c.RecordCount
)
select EntryType,
dateadd(mm, row_number() over (order by EntryType, ID) - 1, dt) as dt,
price
from PricesCTE
order by EntryType
option (maxrecursion 0) -- Infinite recursion, default limit is 100
Here is the SqlFiddle showing this work.
A couple of things:
Upvotes: 3
Reputation: 6205
Not sure if that can be done by CTE, since I can not tell any logic between EntryType and # of row.
For the question, I think it's easier to just build a temp table with number of row you want
DECLARE @Entry TABLE(EntryType INT, seq INT)
INSERT INTO @Entry (EntryType , seq) VALUES
(4,1)
,(5,1)
,(5,2)
,(6,1)
...
,(7,1)
..
,(7,9)
After that, a simple query will get the same result
SELECT t.EntryType , DATEADD(MONTH,e.seq, t.dt) as dt,t.Price
FROM YourTable t
INNER JOIN @Entry e
ON t.EntryType = e.EntryType
Upvotes: 1