dsu*_*sum 4 sql-server-2008 sql-server
我正在尝试编写一个查询来获取表中状态的持续时间。此查询需要在 SQL Server 2008 中工作。
假设我有下表:
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-08
Run Code Online (Sandbox Code Playgroud)
我想得到以下结果
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 NULL
Run Code Online (Sandbox Code Playgroud)
基本上我想在它改变之前获取值的持续时间。
我正在接近某个地方,但仍然无法弄清楚:
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 RecordDate
Run Code Online (Sandbox Code Playgroud)
我知道,SQL Server 2012中具有LAG
和LEAD
功能,但由于我处理SQL Server 2008中,我无法使用它。
请指教
这是生成示例数据的 SQL 语句
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
Run Code Online (Sandbox Code Playgroud)
[更新] 感谢大家的投入。我想在这里澄清一些问题,b/c 我在这里简化了很多事情,这样我就不会给我正在处理的问题增加额外的复杂性。背景是我有一个表格,记录了大量车辆的故障灯指示 (MIL) 状态。此 MIL 状态信息会根据多种因素不定期记录。我想得到的是车辆 MIL 状态开启时的持续时间(值为 1)。该值可以是 -1(未定义)或 0(关闭)。
最初当我发布这个问题时,我认为有简单的 sql 语句解决方案,而不是使用带有 Cursor 的 T-SQL 函数......如果我可以使用 sql 语句 b/c 它与其他第三方集成有很多优点更好地报告应用程序。如果没有 SQL 2012 分析函数,这看起来很难做到。即使有 SQL 语句解决方案,我现在也担心它会太复杂而无法理解和维护。
【更新2】希望还是有人提供基于sql查询的解决方案。但是,由于我的项目时间限制,我现在编写了一个函数来解决这个问题。
CREATE Function GetRateReport (@StartDate DateTime, @EndDate DateTime)
RETURNS @ResultSet TABLE
(
[RecordDate] DateTime,
[Value] int,
[Duration] DateTime
) AS
BEGIN
DECLARE @PreviousValue INT;
DECLARE @EarliestRecordDate DateTime;
DECLARE @CurrentValue INT;
DECLARE @CurrentRecordDate DateTime;
--Open a cursor to get source data
DECLARE sourceCursor CURSOR LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT RecordDate, Value
FROM RateTable
WHERE RecordDate BETWEEN @StartDate AND @EndDate
ORDER BY RecordDate;
--Get the first record
OPEN sourceCursor
FETCH NEXT FROM sourceCursor INTO @CurrentRecordDate, @CurrentValue;
--Initize value
SET @EarliestRecordDate = @CurrentRecordDate;
SET @PreviousValue = @CurrentValue;
WHILE(@@Fetch_Status = 0) -- check for more row
BEGIN
-- Insert result when value changed
IF @CurrentValue <> @PreviousValue
BEGIN
INSERT INTO @ResultSet(RecordDate, Value, Duration)
VALUES (@EarliestRecordDate, @PreviousValue,
@CurrentRecordDate - @EarliestRecordDate);
SET @EarliestRecordDate = @CurrentRecordDate;
SET @PreviousValue = @CurrentValue;
END
FETCH NEXT FROM sourceCursor INTO @CurrentRecordDate, @CurrentValue;
END
--Edge case, retrieve the last value with duration up to current date
INSERT INTO @ResultSet(RecordDate, Value, Duration)
VALUES (@CurrentRecordDate, @CurrentValue, GETDATE() - @CurrentRecordDate);
RETURN
END
GO
--Example
Select [RecordDate], [Value],
DateDiff(day, '1900-01-01', [Duration]) as 'Day Duration'
from GetRateReport('2012-01-01', '2012-01-31')
GO
Run Code Online (Sandbox Code Playgroud)
此解决方案假定Value
每个RecordDate
. 使用调优的索引性能会更好,并且可能会使用临时表或表变量破坏进程。我将您的脚本用于测试数据。输出可能不是您想要的那样,但让您接近的过程很重要 - 它的工作原理是将行过滤为仅开始间隔的行,然后通过从结果中偏移结果来制作结束日期前一步。
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;
Run Code Online (Sandbox Code Playgroud)
输出:
值 StartDate EndDate 持续时间 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
归档时间: |
|
查看次数: |
16351 次 |
最近记录: |