这是表结构:
TABLE TestTable
(
[Id] [uniqueidentifier] NOT NULL,
[Quality] [tinyint] NULL,
[UtcTimeStamp] [datetime2](7) NOT NULL,
[Value] [varbinary](max) NULL
)
我想要达到的目标是:对于from
的指定时间范围(to
- UtcTimeStamp
),首先我将查询位于该时间范围内的所有数据。然后,继续在此规则后的to
时间范围内查询数据:
Quality
有三个值:1,2,3 Quality
之后的第一个数据to
为3,则只需将此一个查询结果与上述范围结果合并。Quality
之后的第一个数据to
为2,则继续查询UtcTimeStamp
为3的下一行(Quality
之后)。最后,结合这两个查询结果具有上述范围的结果。Quality
之后的第一个数据to
为1,则继续查询UtcTimeStamp
为2和3的下一行(此Quality
之后) ,将这三个查询结果与上述范围结果相结合。以上所有作业都包含在一个存储过程中,并且尽可能具有性能。
我对存储过程语法不是很熟悉,并试图存储一些中间变量并使用IF
ELSE
语法来组合所有结果,只是未能使句子有效。
以下是演示内容:
对于R1:
像这样的数据库
Id(fake) UtcTimeStamp(fake) Quality Value
1s-.. 1 1 0x...
1s-.. 2 2 0x...
1s-.. 3 2 0x...
1s-.. 4 3 0x...
1s-.. 5 3 0x...
1s-.. 6 2 0x...
如果我希望查询1到4的时间范围,那么结果应为:
Id(fake) UtcTimeStamp(fake) Quality Value
1s-.. 1 1 0x...
1s-.. 2 2 0x...
1s-.. 3 2 0x...
1s-.. 4 3 0x...
1s-.. 5 3 0x...
对于R2:
像这样的数据库
Id(fake) UtcTimeStamp(fake) Quality Value
1s-.. 1 1 0x...
1s-.. 2 2 0x...
1s-.. 3 2 0x...
1s-.. 4 3 0x...
1s-.. 5 2 0x...
1s-.. 6 2 0x...
1s-.. 7 1 0x...
1s-.. 8 3 0x...
如果我希望查询1到4的时间范围,那么结果应为:
Id(fake) UtcTimeStamp(fake) Quality Value
1s-.. 1 1 0x...
1s-.. 2 2 0x...
1s-.. 3 2 0x...
1s-.. 4 3 0x...
1s-.. 5 2 0x...
1s-.. 8 3 0x...
对于R3:
像这样的数据库
Id(fake) UtcTimeStamp(fake) Quality Value
1s-.. 1 1 0x...
1s-.. 2 2 0x...
1s-.. 3 2 0x...
1s-.. 4 3 0x...
1s-.. 5 1 0x...
1s-.. 6 2 0x...
1s-.. 7 1 0x...
1s-.. 8 3 0x...
如果我希望查询1到4的时间范围,那么结果应为:
Id(fake) UtcTimeStamp(fake) Quality Value
1s-.. 1 1 0x...
1s-.. 2 2 0x...
1s-.. 3 2 0x...
1s-.. 4 3 0x...
1s-.. 5 1 0x...
1s-.. 6 2 0x...
1s-.. 8 3 0x...
程序应该是这样的:
CREATE PROCEDURE [ProcedureName] @Id as uniqueidentifier, @StartTime as datetime2, @EndTime as datetime2 AS ...
答案 0 :(得分:0)
您可以尝试以下操作。我只是尝试先生成一些演示数据:
-- Create demo data
CREATE TABLE dbo.temp
(
[Id] [uniqueidentifier] NOT NULL,
[Quality] [tinyint] NULL,
[UtcTimeStamp] [datetime2](7) NOT NULL,
[Value] [varbinary](max) NULL
)
INSERT INTO dbo.temp(id, quality,UtcTimeStamp, value)
SELECT NEWID() as id, NTILE(3) OVER(ORDER BY object_id) as quality,
DATEADD(day,-NTILE(3) OVER(ORDER BY object_id),GETUTCDATE()) as UtcTimeStamp,
HASHBYTES(N'SHA1',CONVERT(nvarchar(36),NEWID())) as value
FROM sys.all_objects
您可以尝试此程序来获取所有内容:
-- Doing the stuff inside the proc
CREATE PROCEDURE dbo.yourProcedure
@from datetime2, @to datetime2
AS BEGIN
;WITH cte AS(
-- Prepare data base for the second part of the query
SELECT t.id, t.Quality, t.UtcTimeStamp, t.Value, ROW_NUMBER() OVER(order by t.UtcTimeStamp) as rn
FROM dbo.temp as t
WHERE t.UtcTimeStamp > @to
)
-- Get all data based inside the range of @from and @to
SELECT t.id, t.Quality, t.UtcTimeStamp, t.Value
FROM dbo.temp as t
WHERE t.UtcTimeStamp BETWEEN @from AND @to
UNION ALL -- You can use union all, as you the following records won't already be in the above result set
-- Add all rows which are behind the @to date (prepared in the cte)
SELECT t.id, t.Quality, t.UtcTimeStamp, t.Value
FROM cte as t
WHERE (t.Quality = 3 AND t.rn = 1) -- The first row, if it's quality 3
-- All rows until quality 3, if the first row is quality 2
OR ((t.quality = 2 and t.rn = 1) AND (t.rn <= (SELECT TOP 1 rn FROM cte WHERE quality = 3 ORDER By rn)))
-- All rows until quality 2 or 3, if the first row is quality 1
OR ((t.quality = 1 and t.rn = 1) AND (t.rn <= (SELECT TOP 1 rn FROM cte WHERE quality IN(2,3) ORDER By rn)))
END
GO
然后调用结果:
DECLARE @from datetime2 = DATEADD(day,-3,GETUTCDATE()), @to datetime2 = DATEADD(day,-2,GETUTCDATE())
SELECT @from, @to, * FROM dbo.temp
EXEC dbo.yourProcedure @from = @from, @to = @to
GO
之后不要忘记清理。
-- Cleanup
DROP TABLE dbo.temp
答案 1 :(得分:0)
好的,这是我的解决方案:
CREATE PROCEDURE [ProcedureName] @Id as uniqueidentifier, @StartTime as datetime2, @EndTime as datetime2
AS BEGIN
DECLARE @NextRow TABLE
(
[Id] [uniqueidentifier] NOT NULL,
[Quality] [tinyint] NULL,
[UtcTimeStamp] [datetime2](7) NOT NULL,
[Value] [varbinary](max) NULL
)
DECLARE @BoundRows TABLE
(
[Id] [uniqueidentifier] NOT NULL,
[Quality] [tinyint] NULL,
[UtcTimeStamp] [datetime2](7) NOT NULL,
[Value] [varbinary](max) NULL
)
INSERT INTO @NextRow SELECT top 1 * from [JerryTest].[dbo].[TestTable]
where Id = @Id
AND UtcTimeStamp > @EndTime
IF((SELECT TOP 1 Quality FROM @NextRow) = 3)
begin
INSERT INTO @BoundRows SELECT * FROM @NextRow
end
ELSE IF((SELECT TOP 1 Quality FROM @NextRow) = 2)
begin
INSERT INTO @BoundRows SELECT * FROM @NextRow
INSERT INTo @BoundRows SELECT TOP 1 * FROM [JerryTest].[dbo].[TestTable]
WHERE Id = @Id
AND UtcTimeStamp > @EndTime
AND Quality = 3
end
ELSE IF((SELECT TOP 1 Quality FROM @NextRow) = 1)
begin
INSERT INTO @BoundRows SELECT * FROM @NextRow
INSERT INTO @BoundRows SELECT TOP 1 * FROM [JerryTest].[dbo].[TestTable]
WHERE Id = @Id
AND UtcTimeStamp > @EndTime
AND Quality = 2
INSERT INTO @BoundRows SELECT TOP 1 * FROM [JerryTest].[dbo].[TestTable]
WHERE Id = @Id
AND UtcTimeStamp > @EndTime
AND Quality = 3
end
(SELECT * FROM [JerryTest].[dbo].[TestTable]
WHERE Id = @Id
AND UtcTimeStamp >= @StartTime
AND UtcTimeStamp <= @EndTime)
UNION ALL
SELECT * FROM @BoundRows
END
希望这可以帮到你。