SQL 查询 - Select 时间跨度之前的最后一个日期,其中时间跨度中不存在任何日期
SQL Query - Select last date before timespan where no dates exists in timespan
在我的 table 中,我有一个日期时间列和一个标记列。如果时间跨度中没有值,我想 select 时间跨度之前的最新值。如果时间跨度中有值,我不想 return 任何值。
我的查询有以下输入参数:
@StartDate datetime
@EndDate datetime
最重要的查询结果:
- 如果@StartDate 和@EndDate 之间存在数据,则查询不应return 任何结果
- 查询应该return @StartDate IF 之前每个标签的最新值,并且仅当@StartDate 和@EndDate 之间没有结果时
我的问题,我创建了两个查询:
- Returns 时间跨度之前的最新结果。
- Returns 所有结果都在时间跨度内。
想法是SELECT [Values before the timespan] WHERE NOT EXISTS IN [Values in the timespan]
。
我尝试加入这些查询以获得最终结果,但这是我挣扎的地方。
重现步骤(设置):
CREATE TABLE dbo.MyTable(id int IDENTITY(1,1) NOT NULL, Tag nvarchar(200) NOT NULL, StartTime datetime NOT NULL)
DECLARE @day int, @month int, @year int
SELECT @day = 15, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 16, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 18, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 19, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 26, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
重现步骤(查询):
这不应该 return 任何值,因为时间跨度中有值。
DECLARE @day int, @month int, @year int
DECLARE @StartTime datetime
DECLARE @EndTime datetime
SELECT @day = 17, @month = 1, @year = 2015
SET @StartTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)
SET @EndTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1 + 3)
SELECT * FROM (SELECT id, Tag, StartTime FROM dbo.MyTable WHERE StartTime < @StartTime AND Tag NOT IN ( SELECT Tag FROM dbo.MyTable WHERE (StartTime > @StartTime AND StartTime < @EndTime))) as d WHERE EXISTS ( SELECT Tag, StartTime, ROW_NUMBER FROM ( SELECT Tag, StartTime, ROW_NUMBER() OVER(PARTITION BY Tag ORDER BY StartTime DESC) AS ROW_NUMBER FROM dbo.MyTable WHERE StartTime < @StartTime) AS b WHERE ROW_NUMBER = '1')
重现步骤(QUERY2):
这应该在时间跨度之前产生最新的值,因为时间跨度中没有值。
SELECT @day = 21, @month = 1, @year = 2015
SET @StartTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)
SET @EndTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1 + 3)
SELECT * FROM (SELECT id, Tag, StartTime FROM dbo.MyTable WHERE StartTime < @StartTime AND Tag NOT IN ( SELECT Tag FROM dbo.MyTable WHERE (StartTime > @StartTime AND StartTime < @EndTime))) as d WHERE EXISTS ( SELECT Tag, StartTime, ROW_NUMBER FROM ( SELECT Tag, StartTime, ROW_NUMBER() OVER(PARTITION BY Tag ORDER BY StartTime DESC) AS ROW_NUMBER FROM dbo.MyTable WHERE StartTime < @StartTime) AS b WHERE ROW_NUMBER = '1')
编辑:在有关预期结果的部分中添加了 "latest value for each Tag"。
SELECT *
FROM MyTable t
WHERE StartTime < @start
AND id =
(SELECT TOP 1 mt.id FROM MyTable mt WHERE mt.Tag = t.Tag ORDER BY StartTime DESC)
AND NOT EXISTS
(SELECT 1 FROM MyTable WHERE StartTime >= @start AND StartTime <= @end)
ORDER BY StartTime DESC;
以下应该是您要找的大致内容:
SELECT TOP 1 *
FROM [dbo].[MyTable]
WHERE
[StartTime] < @StartTime AND
0 = (
SELECT COUNT(*)
FROM [dbo].[MyTable]
WHERE [StartTime] BETWEEN @StartTime AND @EndTime
)
ORDER BY [StartTime] DESC;
当 @StartTime
和 @EndTime
之间有数据时,0 = (SELECT COUNT(*) ...)
位会导致查询 return 无数据。查询的其余部分只是选择 @StartTime
.
之前的第一行
0 = (SELECT COUNT(*) ...)
与 EXISTS(SELECT 1 ...)
的查询计划比较
这是我修改后的问题的修改答案:
SELECT [A].* FROM [dbo].[MyTable] AS [A]
INNER JOIN (
SELECT [Tag], MAX([StartTime]) AS [StartTime]
FROM [dbo].[MyTable]
WHERE [StartTime] < @StartTime
GROUP BY [Tag]
) AS B ON ([A].[Tag] = [B].[Tag] AND [A].[StartTime] = [B].[StartTime])
WHERE
[A].[StartTime] < @StartTime AND
0 = (
SELECT COUNT(*)
FROM [dbo].[MyTable]
WHERE [StartTime] BETWEEN @StartTime AND @EndTime
)
;
连接子查询计算出 @StartTime
之前每个标签的最新日期并连接回它自己,以便可以返回整行(使用 id
)。
在我的 table 中,我有一个日期时间列和一个标记列。如果时间跨度中没有值,我想 select 时间跨度之前的最新值。如果时间跨度中有值,我不想 return 任何值。
我的查询有以下输入参数:
@StartDate datetime
@EndDate datetime
最重要的查询结果:
- 如果@StartDate 和@EndDate 之间存在数据,则查询不应return 任何结果
- 查询应该return @StartDate IF 之前每个标签的最新值,并且仅当@StartDate 和@EndDate 之间没有结果时
我的问题,我创建了两个查询:
- Returns 时间跨度之前的最新结果。
- Returns 所有结果都在时间跨度内。
想法是SELECT [Values before the timespan] WHERE NOT EXISTS IN [Values in the timespan]
。
我尝试加入这些查询以获得最终结果,但这是我挣扎的地方。
重现步骤(设置):
CREATE TABLE dbo.MyTable(id int IDENTITY(1,1) NOT NULL, Tag nvarchar(200) NOT NULL, StartTime datetime NOT NULL)
DECLARE @day int, @month int, @year int
SELECT @day = 15, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 16, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 18, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 19, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
SELECT @day = 26, @month = 1, @year = 2015
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MyTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
INSERT INTO dbo.MyTable(Tag, StartTime) VALUES('MySuperTag',dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1))
重现步骤(查询):
这不应该 return 任何值,因为时间跨度中有值。
DECLARE @day int, @month int, @year int
DECLARE @StartTime datetime
DECLARE @EndTime datetime
SELECT @day = 17, @month = 1, @year = 2015
SET @StartTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)
SET @EndTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1 + 3)
SELECT * FROM (SELECT id, Tag, StartTime FROM dbo.MyTable WHERE StartTime < @StartTime AND Tag NOT IN ( SELECT Tag FROM dbo.MyTable WHERE (StartTime > @StartTime AND StartTime < @EndTime))) as d WHERE EXISTS ( SELECT Tag, StartTime, ROW_NUMBER FROM ( SELECT Tag, StartTime, ROW_NUMBER() OVER(PARTITION BY Tag ORDER BY StartTime DESC) AS ROW_NUMBER FROM dbo.MyTable WHERE StartTime < @StartTime) AS b WHERE ROW_NUMBER = '1')
重现步骤(QUERY2):
这应该在时间跨度之前产生最新的值,因为时间跨度中没有值。
SELECT @day = 21, @month = 1, @year = 2015
SET @StartTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1)
SET @EndTime = dateadd(mm, (@year - 1900) * 12 + @month - 1 , @day - 1 + 3)
SELECT * FROM (SELECT id, Tag, StartTime FROM dbo.MyTable WHERE StartTime < @StartTime AND Tag NOT IN ( SELECT Tag FROM dbo.MyTable WHERE (StartTime > @StartTime AND StartTime < @EndTime))) as d WHERE EXISTS ( SELECT Tag, StartTime, ROW_NUMBER FROM ( SELECT Tag, StartTime, ROW_NUMBER() OVER(PARTITION BY Tag ORDER BY StartTime DESC) AS ROW_NUMBER FROM dbo.MyTable WHERE StartTime < @StartTime) AS b WHERE ROW_NUMBER = '1')
编辑:在有关预期结果的部分中添加了 "latest value for each Tag"。
SELECT *
FROM MyTable t
WHERE StartTime < @start
AND id =
(SELECT TOP 1 mt.id FROM MyTable mt WHERE mt.Tag = t.Tag ORDER BY StartTime DESC)
AND NOT EXISTS
(SELECT 1 FROM MyTable WHERE StartTime >= @start AND StartTime <= @end)
ORDER BY StartTime DESC;
以下应该是您要找的大致内容:
SELECT TOP 1 *
FROM [dbo].[MyTable]
WHERE
[StartTime] < @StartTime AND
0 = (
SELECT COUNT(*)
FROM [dbo].[MyTable]
WHERE [StartTime] BETWEEN @StartTime AND @EndTime
)
ORDER BY [StartTime] DESC;
当 @StartTime
和 @EndTime
之间有数据时,0 = (SELECT COUNT(*) ...)
位会导致查询 return 无数据。查询的其余部分只是选择 @StartTime
.
0 = (SELECT COUNT(*) ...)
与 EXISTS(SELECT 1 ...)
的查询计划比较
这是我修改后的问题的修改答案:
SELECT [A].* FROM [dbo].[MyTable] AS [A]
INNER JOIN (
SELECT [Tag], MAX([StartTime]) AS [StartTime]
FROM [dbo].[MyTable]
WHERE [StartTime] < @StartTime
GROUP BY [Tag]
) AS B ON ([A].[Tag] = [B].[Tag] AND [A].[StartTime] = [B].[StartTime])
WHERE
[A].[StartTime] < @StartTime AND
0 = (
SELECT COUNT(*)
FROM [dbo].[MyTable]
WHERE [StartTime] BETWEEN @StartTime AND @EndTime
)
;
连接子查询计算出 @StartTime
之前每个标签的最新日期并连接回它自己,以便可以返回整行(使用 id
)。