Reputation: 139
I have table with date ranges
and i need to add rows between this ranges. I must granulate this table to minutes. How can i add this extra rows
Upvotes: 0
Views: 737
Reputation: 86716
The recursive CTE option from @MatthewBaker would only need minor changes to meet your needs.
WITH
by_minute
AS
(
SELECT *, datetime_from, minute_marker FROM your_table
UNION ALL
SELECT *, DATEADD(minute, 1, minute_marker) FROM by_minute WHERE DATEADD(minute, 1, minute_marker) < datetime_to
)
SELECT
*
FROM
by_minute
OPTION
(MAXRECURSION 0)
The OPTION (MAXRECURSION 0)
allows SQL Server to keep recursively generating the minutes beyond the default of 100. Still, I would not recommend this if the intervals being generated are more than a few hundred minutes long (maybe up to one day [1440 minutes]).
In such a case the simpler approach would be to utilise a table of numbers, and simply join on to that.
An example for creating such a table could be : https://www.mssqltips.com/sqlservertip/4176/the-sql-server-numbers-table-explained--part-1/
From there, you just join on the number of row that you need...
SELECT
yourTable.*,
DATEADD(minute, Numbers.[Number], yourTable.datetime_from) AS minute_marker
FROM
yourTable
INNER JOIN
dbo.Numbers
ON Numbers.[Number] >= 0
AND Numbers.[Number] < DATEDIFF(minute, yourTable.datetime_from, yourTable.datetime_to)
Another recommendation I have is to NOT use 59th second to represent the end of a minute. What if you get data at 59.600 seconds? That's after then end of the minute but before the start of the new one? Instead use markers that are Inclusive Start and Exclusive End...
The first minute of 2012 = '2012-01-01 00:00:00.000' -> '2012-01-01 00:01:00.000'
The final minute of 2012 = '2012-12-31 23:59:00.000' -> '2013-01-01 00:00:00.000'
With such a structure you only ever need my_point_in_time >= start AND my_point_in_time < end
, and you never need worry about the precision of the datatypes being used.
(It also matches human natural language. When we say things like between 1 and 2
we most often mean >= 1 AND < 2
.)
Upvotes: 1
Reputation: 2729
If you use the following:
WITH cte
AS (SELECT CAST('2017-01-01 00:00:00' AS DATETIME) AS startTime
UNION ALL
SELECT DATEADD(MINUTE, 1, startTime)
FROM cte
WHERE startTime < '2017-01-02 00:00:00'
)
SELECT *
FROM cte
OPTION (MAXRECURSION 0)
It will give you a minute by minute result. Substitute in the range you want. You can then use that as a basis to write an insert. Iterative CTE's aren't the most efficient, but probably the easiest
Upvotes: 0