我的查询(如下)不起作用。我知道为什么它不起作用,但我需要帮助修复它。基本上我正在努力做到以下几点:
从FireEvent获取所有行 获取HitEvent的所有行,这些行在FireEvent的-5/5秒内,如果HitEvent已经“配对”,那么FireEvent则不希望再次包含它。基本上,我不希望任何HitEvent不止一次出现在我的查询中!我被告知在SQL聊天室里玩RANK,如果我能弄清楚如何在我的子查询中包含来自FireEvent的EventTime,它似乎会起作用...
无论如何,这是查询...
SELECT FireEvent.ExerciseID,
FireEvent.FireEventID,
tempHitEvent.HitEventID,
FireEvent.AssociatedPlayerID,
tempHitEvent.AssociatedPlayerID,
FireEvent.EventTime,
tempHitEvent.EventTime,
FireEvent.Longitude,
FireEvent.Latitude,
tempHitEvent.Longitude,
tempHitEvent.Latitude,
tempHitEvent.HitResult,
FireEvent.AmmunitionCode,
FireEvent.AmmunitionSource,
FireEvent.FireEventID,
0 AS 'IsArtillery'
FROM FireEvent
LEFT JOIN (SELECT HitEvent.*,
FireEvent.FireEventID,
Rank()
OVER (
ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
INNER JOIN FireEvent
ON FireEvent.EventTime BETWEEN
Dateadd(millisecond, -5000,
HitEvent.EventTime) AND
Dateadd(millisecond,
5000, HitEvent.EventTime) AND HitEvent.FiringPlayerID = FireEvent.PlayerID
AND HitEvent.AmmunitionCode =
FireEvent.AmmunitionCode
AND HitEvent.ExerciseID =
'D289D508-1479-4C17-988C-5F6A847AE51E'
AND FireEvent.ExerciseID =
'D289D508-1479-4C17-988C-5F6A847AE51E'
AND HitEvent.HitResult NOT IN ( 0, 1 ) ) AS
tempHitEvent
ON (
RankValue = 1
AND tempHitEvent.FireEventID =
FireEvent.FireEventID
)
WHERE FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
ORDER BY HitEventID
答案 0 :(得分:1)
我相信以下内容将满足您的要求,假设我没有介绍错误。我无法测试代码,但我相信我的概念是正确的。你可能很容易找到一个错字或其他一些愚蠢的错误。但我相信您只需要在CTE中加入一次,您就可以直接从CTE中选择最终结果。
关于如何将点击事件与火灾事件进行匹配,您并不是非常具体。你永远不希望命中事件出现两次,所以我按HitEventID进行分区。我假设你想以最小化两个事件时间之间差异的方式配对它们。所以我按两个事件之间差异的绝对值排序,并且我通过FireEventID打破任何关系。
编辑 - 将HitResult过滤器从where子句移动到外连接子句 EDIT2 - 附加到最后的where子句以保留所有不匹配的FireEvent(HitEventID为null)
with RankedHits as (
select F.ExcerciseID,
F.FireEventID,
H.HitEventID,
F.AssociatedPlayerID as FireAssociatedPlayerID,
H.AssociatedPlayerID as HitAssociatedPlayerID,
F.EventTime as FireEventTime,
H.EventTime as HitEventTime,
F.Longitude as FireLongitude,
F.Latitude as FireLatitude,
H.Longitude as HitLongitude,
H.Latitude as HitLatitude,
H.HitResult,
F.AmmunitionCode,
F.AmmunitionSource,
F.FireEventID,
rank() over( partition by HitEventID
order by abs( datediff( ms, H.EventTime, F.EventTime ) ),
F.FireEventID
) as HitRank
from FireEvent F
left join HitEvent H
on F.AmmunitionCode = H.AmmunitionCode
and F.PlayerID = H.FiringPlayerID
and F.ExcerciseID = H.ExcerciseID
and H.HitResult not in( 0, 1 )
and F.EventTime between dateadd(millisecond, -5000, H.EventTime)
and dateadd(millisecond, 5000, H.EventTime)
where F.ExcerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
)
select ExcerciseID,
FireEventID,
HitEventID,
FireAssociatedPlayerID,
HitAssociatedPlayerID,
FireEventTime,
HitEventTime,
FireLongitude,
FireLatitude,
HitLongitude,
HitLatitude,
HitResult,
AmmunitionCode,
AmmunitionSource,
FireEventID,
0 as IsArtillery
from RankedHits
where HitRank=1 or HitEventID is null
编辑以回应评论
以下是从您的评论链接派生的固定代码。关键错误是HitRank = 1过滤器从最后丢失。也在选择列表中替换了HitRank的HitResult。
没有必要,但我还将玩家运动ID与火灾事件运动ID进行了比较,而不是字符串文字。这样可以更容易在将来更改练习ID,因为字符串文字现在只在查询中出现一次。
我更喜欢CTE语法,但我保留了FROM子句中的内联视图语法,如您所愿。
EDIT2 - 附加到最后的where子句以保留所有不匹配的FireEvent(HitEventID为null)
INSERT #Events (
exerciseid,
fireeventid,
hiteventid,
firingplayerid,
hitplayerid,
firingplayerunitid,
hitplayerunitid,
firingplayerassociatedplayerid,
hitplayerassociatedplayerid,
firingtime,
hittime,
firinglongitude,
firinglatitude,
hitlongitude,
hitlatitude,
hitresult,
ammunitioncode,
ammunitionsource,
eventid,
isartillery
)
(
SELECT ExerciseID, FireEventID, HitEventID, FiringPlayerID, HitPlayerID,
FiringUnitID, HitUnitID, FireAssociatedPlayerID, HitAssociatedPlayerID,
FireEventTime, HitEventTime, FireLongitude, FireLatitude, HitLongitude,
HitLatitude, HitRank, AmmunitionCode, AmmunitionSource, EventID, 0
FROM (
select FireEvent.ExerciseID,
FireEvent.FireEventID,
HitEvent.HitEventID,
FireEvent.PlayerID as FiringPlayerID,
HitEvent.PlayerID as HitPlayerID,
FiringPlayer.UnitID as FiringUnitID,
HitPlayer.UnitID as HitUnitID,
FireEvent.AssociatedPlayerID as FireAssociatedPlayerID,
HitEvent.AssociatedPlayerID as HitAssociatedPlayerID,
FireEvent.EventTime as FireEventTime,
HitEvent.EventTime as HitEventTime,
FireEvent.Longitude as FireLongitude,
FireEvent.Latitude as FireLatitude,
HitEvent.Longitude as HitLongitude,
HitEvent.Latitude as HitLatitude,
HitEvent.HitResult,
FireEvent.AmmunitionCode,
FireEvent.AmmunitionSource,
FireEvent.FireEventID AS 'EventID',
rank() over( partition by HitEventID
order by abs( datediff( ms, HitEvent.EventTime, FireEvent.EventTime ) ),
FireEvent.FireEventID
) as HitRank
from FireEvent
left join HitEvent
on FireEvent.ExerciseID = HitEvent.ExerciseID
and FireEvent.AmmunitionCode = HitEvent.AmmunitionCode
and FireEvent.PlayerID = HitEvent.FiringPlayerID
and HitEvent.HitResult not in( 0, 1 )
and FireEvent.EventTime between dateadd(millisecond, -5000, HitEvent.EventTime)
and dateadd(millisecond, 5000, HitEvent.EventTime)
LEFT JOIN Player FiringPlayer
ON FiringPlayer.PlayerID = FireEvent.PlayerID
AND FiringPlayer.ExerciseID = FireEvent.ExcerciseID
LEFT JOIN Player HitPlayer
ON HitPlayer.PlayerID = HitEvent.PlayerID
AND HitPlayer.ExerciseID = FireEvent.ExcerciseID
where FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
) as temp
where HitRank=1 or HitEventID is null
)
答案 1 :(得分:1)
问题在于您使用的是RANK()
而不是ROW_NUMBER()
。如果任何hitevent与匹配的事件的数量相同,则它们的排名均为1,这意味着您将获得重复。根据我们在聊天中的对话,将整个查询包装在子查询中,现在摆脱内部子查询并进行直接连接,然后从外部查询中限制为HitRank = 1
,您将成为黄金。
答案 2 :(得分:0)
我不确定这是否是您想要的,但您可以在查询开头使用CTE
With cte as (
SELECT FireEvent.ExerciseID,
FireEvent.FireEventID,
tempHitEvent.HitEventID,
FireEvent.AssociatedPlayerID,
tempHitEvent.AssociatedPlayerID,
FireEvent.EventTime,
tempHitEvent.EventTime,
FireEvent.Longitude,
FireEvent.Latitude,
tempHitEvent.Longitude,
tempHitEvent.Latitude,
tempHitEvent.HitResult,
FireEvent.AmmunitionCode,
FireEvent.AmmunitionSource,
FireEvent.FireEventID,
0 AS 'IsArtillery'
FROM FireEvent )
Select * from CTE
LEFT JOIN (SELECT HitEvent.*,
FireEvent.FireEventID,
Rank()
OVER (
ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
INNER JOIN FireEvent
ON FireEvent.EventTime BETWEEN
Dateadd(millisecond, -5000,
HitEvent.EventTime) AND
Dateadd(millisecond,
5000, HitEvent.EventTime) AND HitEvent.FiringPlayerID = FireEvent.PlayerID
AND HitEvent.AmmunitionCode =
FireEvent.AmmunitionCode
AND HitEvent.ExerciseID =
'D289D508-1479-4C17-988C-5F6A847AE51E'
AND FireEvent.ExerciseID =
'D289D508-1479-4C17-988C-5F6A847AE51E'
AND HitEvent.HitResult NOT IN ( 0, 1 ) ) AS
tempHitEvent
ON (
RankValue = 1
AND tempHitEvent.FireEventID =
FireEvent.FireEventID
)
WHERE FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
ORDER BY HitEventID
答案 3 :(得分:0)
以下大致简化的示例应该产生最佳对。考虑到当前时间,它可能会产生沙鼠,我不会注意到。
declare @Fires as Table ( FireId Int Identity, FireTime Int )
insert into @Fires ( FireTime ) values
( 1 ), ( 2 ), ( 3 ), ( 5 ), ( 8 ), ( 13 ), ( 21 ), ( 34 )
declare @Hits as Table ( HitId Int Identity, HitTime Int )
insert into @Hits ( HitTime ) values
( 5 ), ( 7 ), ( 12 ), ( 12 ), ( 20 ), ( 21 ), ( 30 )
-- Create a temporary table of all possible pairs meeting the time criteria.
select F.*, Dense_Rank() over ( partition by H.HitTime, H.HitId order by F.FireTime, F.FireId ) as [FireRank],
H.*, Dense_Rank() over ( order by H.HitTime, H.HitId ) as [HitRank]
into #Pairs
from @Fires as F inner join
@Hits as H on F.FireTime between H.HitTime - 5 and H.HitTime + 5
-- Clean up the pairs.
declare @HitRank as Int = 1
declare @MaxHitRank as Int = ( select Max( HitRank ) from #Pairs )
declare @MinFireRank as Int
while ( @HitRank <= @MaxHitRank )
begin
select @MinFireRank = Min( FireRank ) from #Pairs where HitRank = @HitRank
delete from #Pairs
where
-- It is not the first FireRank for the current HitRank .
( HitRank = @HitRank and FireRank > @MinFireRank ) or
-- Once we pair a fire event don't pair it against another hit event.
( HitRank > @HitRank and FireId in ( select FireId from #Pairs where HitRank = @HitRank and FireRank = @MinFireRank ) )
set @HitRank = @HitRank + 1
end
-- Select the paired events.
select FireId, FireTime, HitId, HitTime
from #Pairs
union
-- Add in the unpaired fire events.
select FireId, FireTime, NULL, NULL
from @Fires
where FireId not in ( select FireId from #Pairs )
order by FireTime, FireId, HitTime, HitId
drop table #Pairs