patternsqlMinor
Query (duration) different between data value change
Viewed 0 times
queryvaluedifferentbetweendurationdatachange
Problem
I am trying to write a query that would get me the duration of a status in a table. This query needs to work in SQL Server 2008.
Say I have the following table:
I would like to get the following result
Basically I would like the get the duration when of the value before it changes.
I am getting somewhere close, but still can't figure it out:
I know that SQL Server 2012 has
Please advise
Here is the SQL statement that generate the sample data
[Update] Thanks for everyone's inputs. I like to clarify a number of questions here, b/c I simplified many things here so that I won't add extra complexity to the problem that I am worki
Say I have the following table:
Key Value RecordDate
1 1 2012-01-01
2 1 2012-01-02
3 1 2012-01-03
4 5 2012-01-05
5 5 2012-01-05 12:00:00
6 12 2012-01-06
7 1 2012-01-07
8 1 2012-01-08I would like to get the following result
Value StartDate EndDate Duration
1 2012-01-01 2012-01-05 4 days
5 2012-01-05 2012-01-06 1 days
12 2012-01-06 2012-01-07 1 days
1 2012-01-07 NULL NULLBasically I would like the get the duration when of the value before it changes.
I am getting somewhere close, but still can't figure it out:
SELECT [Key], [Value],
MIN(RecordDate) OVER(PARTITION BY [Value]) as 'StarDate',
MAX(RecordDate) OVER(PARTITION BY [Value]) as 'EndDate',
DATEDIFF(day, (MIN(RecordDate) OVER(PARTITION BY [Value])),
(MAX(RecordDate) OVER(PARTITION BY [Value])))
FROM [RateTable]
Order by RecordDateI know that SQL Server 2012 has
LAG and LEAD function, but since I am deal with SQL Server 2008, I can't use it.Please advise
Here is the SQL statement that generate the sample data
CREATE TABLE RateTable(
[Key] [int] IDENTITY(1,1) NOT NULL,
[Value] [int] NULL,
[RecordDate] [DateTime] NULL
)
GO
INSERT INTO [RateTable] VALUES (1, '2012-01-01');
INSERT INTO [RateTable] VALUES (1, '2012-01-02');
INSERT INTO [RateTable] VALUES (1, '2012-01-03');
INSERT INTO [RateTable] VALUES (5, '2012-01-04');
INSERT INTO [RateTable] VALUES (5, '2012-01-05 12:00:00');
INSERT INTO [RateTable] VALUES (12, '2012-01-06');
INSERT INTO [RateTable] VALUES (1, '2012-01-07');
INSERT INTO [RateTable] VALUES (1, '2012-01-08');
GO[Update] Thanks for everyone's inputs. I like to clarify a number of questions here, b/c I simplified many things here so that I won't add extra complexity to the problem that I am worki
Solution
This solution assumes there is only a single
Output:
Value StartDate EndDate Duration
1 2012-01-01 00:00:00.000 2012-01-04 00:00:00.000 4
5 2012-01-04 00:00:00.000 2012-01-06 00:00:00.000 3
12 2012-01-06 00:00:00.000 2012-01-07 00:00:00.000 2
1 2012-01-07 00:00:00.000 NULL NULL
Value for each RecordDate. Performance will be better with tuned indexes, and probably breaking up the process using a temporary table or table variable. I used your script for test data. The output may not be exactly how you want it, but the process to get you close is what's important -- it works by filtering the rows to only the rows that start an interval, and then fabricates the end date by offsetting the results from the previous step.WITH a AS
(
SELECT
Value,
RecordDate,
ROW_NUMBER() OVER(ORDER BY RecordDate) AS RN
FROM [dbo].[RateTable] rt
),
b AS
(
SELECT
a1.Value,
a1.RecordDate,
ROW_NUMBER() OVER(ORDER BY a1.RecordDate) AS RN
FROM a a1
LEFT OUTER JOIN a a2 ON a2.RN = a1.RN - 1
WHERE
(a1.Value != a2.Value) OR
(a2.RN IS NULL)
)
SELECT
b1.Value,
b1.RecordDate AS StartDate,
b2.RecordDate AS EndDate,
DATEDIFF(DAY, b1.RecordDate, b2.RecordDate) + 1 AS Duration /* Fixme? */
FROM b b1
LEFT OUTER JOIN b b2 ON b2.RN = b1.RN + 1
ORDER BY b1.RecordDate;Output:
Value StartDate EndDate Duration
1 2012-01-01 00:00:00.000 2012-01-04 00:00:00.000 4
5 2012-01-04 00:00:00.000 2012-01-06 00:00:00.000 3
12 2012-01-06 00:00:00.000 2012-01-07 00:00:00.000 2
1 2012-01-07 00:00:00.000 NULL NULL
Code Snippets
WITH a AS
(
SELECT
Value,
RecordDate,
ROW_NUMBER() OVER(ORDER BY RecordDate) AS RN
FROM [dbo].[RateTable] rt
),
b AS
(
SELECT
a1.Value,
a1.RecordDate,
ROW_NUMBER() OVER(ORDER BY a1.RecordDate) AS RN
FROM a a1
LEFT OUTER JOIN a a2 ON a2.RN = a1.RN - 1
WHERE
(a1.Value != a2.Value) OR
(a2.RN IS NULL)
)
SELECT
b1.Value,
b1.RecordDate AS StartDate,
b2.RecordDate AS EndDate,
DATEDIFF(DAY, b1.RecordDate, b2.RecordDate) + 1 AS Duration /* Fixme? */
FROM b b1
LEFT OUTER JOIN b b2 ON b2.RN = b1.RN + 1
ORDER BY b1.RecordDate;Context
StackExchange Database Administrators Q#46641, answer score: 7
Revisions (0)
No revisions yet.