SQL self join table 以查找符合条件的下一行
SQL self join table to find next row that matches a condition
我有一个 table,其中包含车辆跟踪器生成的事件。 table 称为 tMain(因为它是我的主 table),这里重要的列是 cVehicleId、cFixedId(事件 ID)和 cDateTime。 ID 是整数,cDateTime 是 datetime2(7)。
cFixedId 可以是 NEWTRIP (67)、DEPART (63)、STOP (64)、PROCEED (65) 和 DELIVER (66) 之一。这通常也是事件生成的顺序。
table 包含车队生成的事件。车辆中的跟踪器也提供 DateTime,因此 table 通常但不一定 100%(因为跟踪器可能不是 100% 同步)由 DateTime 排序。每一辆车的事件不会是连续的(因为有很多车辆并行报告),但它们会按时间排序。
示例(1 辆车):
cId cDateTime cVehicleId cFixedId
62462946 2020-06-01 15:47:35.000 27 66
62462476 2020-06-01 15:37:58.000 27 65
62461602 2020-06-01 15:14:43.000 27 64
62461422 2020-06-01 15:11:08.000 27 63
62461407 2020-06-01 15:10:47.000 27 67
我想要的是 returns 所有 DELIVER 事件连同前面的 DEPART(或可能是 NEWTRIP)事件的查询,以查看行程花费了多长时间。这应该看起来像这样:
cVehicleId cFixedId cDateTime cFixedId cDateTime
27 67 2020-06-01 15:10:47.000 66 2020-06-01 15:47:35.000
我尝试的是查找所有 DEPART 事件,然后向前搜索具有相同 VehicleId 且具有 EventId DELIVER 的下一个事件。或者查找所有 DELIVER 事件并向后搜索具有相同 VehicleId 的最近的 DEPART 事件。
我一直在尝试很多使用自连接的查询,也考虑过使用 LEAD 或 LAG 函数,但我认为这些不会对我有帮助。我就是无法让它工作。
我目前拥有的是:
DECLARE @DEPART int = 63;
DECLARE @DELIVER int = 66;
DECLARE @StartDate DATE = '2020-05-01';
DECLARE @StopDate DATE = '2020-05-02';
select * from
(select cVehicleid, cDatetime, cFixedId from tMain where cFixedId = @DEPART and cDateTime > @StartDate and cDateTime < @StopDate) as t1
inner join
(select top(1) cVehicleId, cDatetime, cFixedId from tMain where cFixedId = @DELIVER and cDateTime > @StartDate and cDateTime < @StopDate order by cDateTime) as t2 on t2.cVehicleId = t1.cVehicleId and t2.cDateTime > t1.cDateTime
不过,这个returns没什么。
我不明白我做错了什么,我不知道如何继续。也许还有我不知道的更好的方法。我在网上进行了大量搜索,但没有找到任何可以引导我找到解决方案的内容。谁能给我提示?
不太重要的额外内容:如果结果按 VehicledId 分组就好了,但这不是绝对必须的。
What I want is a query that returns all DELIVER events together with the preceding DEPART (or maybe NEWTRIP) events, to see how long the trip took.
如果我没理解错的话,你可以用apply
:
select d.*, previous.*
from tmain d outer apply
(select top (1) e.*
from tmain e
where e.cVehicleId = d.cVehicleId and
e.cFixedId in ('DEPART', 'NEWTRIP') and
e.cDateTime < d.cDateTime
order by e.cDateTime desc
) previous
where d.ceventid = 'DELIVER';
为清楚起见,这里使用字符串版本。
我有一个 table,其中包含车辆跟踪器生成的事件。 table 称为 tMain(因为它是我的主 table),这里重要的列是 cVehicleId、cFixedId(事件 ID)和 cDateTime。 ID 是整数,cDateTime 是 datetime2(7)。 cFixedId 可以是 NEWTRIP (67)、DEPART (63)、STOP (64)、PROCEED (65) 和 DELIVER (66) 之一。这通常也是事件生成的顺序。 table 包含车队生成的事件。车辆中的跟踪器也提供 DateTime,因此 table 通常但不一定 100%(因为跟踪器可能不是 100% 同步)由 DateTime 排序。每一辆车的事件不会是连续的(因为有很多车辆并行报告),但它们会按时间排序。
示例(1 辆车):
cId cDateTime cVehicleId cFixedId
62462946 2020-06-01 15:47:35.000 27 66
62462476 2020-06-01 15:37:58.000 27 65
62461602 2020-06-01 15:14:43.000 27 64
62461422 2020-06-01 15:11:08.000 27 63
62461407 2020-06-01 15:10:47.000 27 67
我想要的是 returns 所有 DELIVER 事件连同前面的 DEPART(或可能是 NEWTRIP)事件的查询,以查看行程花费了多长时间。这应该看起来像这样:
cVehicleId cFixedId cDateTime cFixedId cDateTime
27 67 2020-06-01 15:10:47.000 66 2020-06-01 15:47:35.000
我尝试的是查找所有 DEPART 事件,然后向前搜索具有相同 VehicleId 且具有 EventId DELIVER 的下一个事件。或者查找所有 DELIVER 事件并向后搜索具有相同 VehicleId 的最近的 DEPART 事件。
我一直在尝试很多使用自连接的查询,也考虑过使用 LEAD 或 LAG 函数,但我认为这些不会对我有帮助。我就是无法让它工作。
我目前拥有的是:
DECLARE @DEPART int = 63;
DECLARE @DELIVER int = 66;
DECLARE @StartDate DATE = '2020-05-01';
DECLARE @StopDate DATE = '2020-05-02';
select * from
(select cVehicleid, cDatetime, cFixedId from tMain where cFixedId = @DEPART and cDateTime > @StartDate and cDateTime < @StopDate) as t1
inner join
(select top(1) cVehicleId, cDatetime, cFixedId from tMain where cFixedId = @DELIVER and cDateTime > @StartDate and cDateTime < @StopDate order by cDateTime) as t2 on t2.cVehicleId = t1.cVehicleId and t2.cDateTime > t1.cDateTime
不过,这个returns没什么。
我不明白我做错了什么,我不知道如何继续。也许还有我不知道的更好的方法。我在网上进行了大量搜索,但没有找到任何可以引导我找到解决方案的内容。谁能给我提示?
不太重要的额外内容:如果结果按 VehicledId 分组就好了,但这不是绝对必须的。
What I want is a query that returns all DELIVER events together with the preceding DEPART (or maybe NEWTRIP) events, to see how long the trip took.
如果我没理解错的话,你可以用apply
:
select d.*, previous.*
from tmain d outer apply
(select top (1) e.*
from tmain e
where e.cVehicleId = d.cVehicleId and
e.cFixedId in ('DEPART', 'NEWTRIP') and
e.cDateTime < d.cDateTime
order by e.cDateTime desc
) previous
where d.ceventid = 'DELIVER';
为清楚起见,这里使用字符串版本。