Sql 联接内的相关子查询?
我有一个查询,其中我需要一个连接中的相关子查询。我说需要,我的意思是我想我需要它在那里。。。我该怎么做?我的查询如下,我得到了“多部分标识符”字段名出现在“无法绑定”错误。。。如何将此查询更改为有效Sql 联接内的相关子查询?,sql,sql-server-2008,subquery,correlated-subquery,Sql,Sql Server 2008,Subquery,Correlated Subquery,我有一个查询,其中我需要一个连接中的相关子查询。我说需要,我的意思是我想我需要它在那里。。。我该怎么做?我的查询如下,我得到了“多部分标识符”字段名出现在“无法绑定”错误。。。如何将此查询更改为有效 SELECT FireEvent.ExerciseID, FireEvent.FireEventID, tempHitEvent.HitEventID, FireEvent.AssociatedPlayerID, tempHitEven
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
WHERE 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
交叉应用在这种情况下有效
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'
,RankValue
FROM FireEvent
CROSS APPLY (SELECT HitEvent.*,
FireEvent.FireEventID,
Rank()
OVER (
ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
WHERE 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 ) )
tempHitEvent
WHERE
RankValue = 1
AND tempHitEvent.FireEventID =
FireEvent.FireEventID
AND FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
ORDER BY HitEventID
交叉应用在这种情况下有效
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'
,RankValue
FROM FireEvent
CROSS APPLY (SELECT HitEvent.*,
FireEvent.FireEventID,
Rank()
OVER (
ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
WHERE 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 ) )
tempHitEvent
WHERE
RankValue = 1
AND tempHitEvent.FireEventID =
FireEvent.FireEventID
AND FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
ORDER BY HitEventID
您不需要相关子查询。您似乎有一个相对简单的连接,尽管同时在几个字段上 下面的FROM子句从引用这两个表的子查询内部提取条件,并将它们移到JOIN子句外部。这与您想要的非常接近,这取决于列组中的分区是否正在执行您期望的操作:
FROM FireEvent fe left outer join
(SELECT HitEvent.*,
Rank() OVER (partition by FiringPlayerID, ExerciseID, FireEventID, FireEventID
ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
WHERE HitEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' AND
HitEvent.HitResult NOT IN ( 0, 1 )
) he
ON he.FiringPlayerID = fe.PlayerId and
he.AmmunitionCode = fe.AmmunitionCode and
fe.EventTime BETWEEN Dateadd(millisecond, -5000, he.EventTime) AND
Dateadd(millisecond, 5000, he.EventTime) AND
fe.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' AND
RankValue = 1 , d
he.FireEventID = fe.FireEventID
您不需要相关子查询。您似乎有一个相对简单的连接,尽管同时在几个字段上 下面的FROM子句从引用这两个表的子查询内部提取条件,并将它们移到JOIN子句外部。这与您想要的非常接近,这取决于列组中的分区是否正在执行您期望的操作:
FROM FireEvent fe left outer join
(SELECT HitEvent.*,
Rank() OVER (partition by FiringPlayerID, ExerciseID, FireEventID, FireEventID
ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
WHERE HitEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' AND
HitEvent.HitResult NOT IN ( 0, 1 )
) he
ON he.FiringPlayerID = fe.PlayerId and
he.AmmunitionCode = fe.AmmunitionCode and
fe.EventTime BETWEEN Dateadd(millisecond, -5000, he.EventTime) AND
Dateadd(millisecond, 5000, he.EventTime) AND
fe.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E' AND
RankValue = 1 , d
he.FireEventID = fe.FireEventID
使用而不是左连接。我不得不把你们的一些条款移走,但下面的内容应该会产生预期的结果
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
OUTER APPLY
( SELECT HitEvent.*, RANK() OVER (ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
WHERE HitEvent.FireEventID = FireEvent.FireEventID
AND 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 = FireEvent.ExerciseID
AND HitEvent.HitResult NOT IN ( 0, 1 )
) AS tempHitEvent
WHERE COALESCE(RankValue, 1) = 1
AND FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
ORDER BY FireEvent.HitEventID
如果您只想在存在匹配的HitEvent的情况下返回结果,请使用交叉应用
<代码>交叉应用是到外部应用
什么内部连接
是到左侧连接
附录 这一切都可以通过使用联接来实现,而无需使用
OUTER APPLY
,方法是不使用子查询来联接HitEvent,然后对所有数据执行RANK
函数,而不仅仅是HitEvent表。所有这些都需要移动到子查询中,以便RANK
函数的结果可以包含在WHERE
子句中
SELECT *
FROM ( SELECT FireEvent.ExerciseID,
FireEvent.FireEventID,
HitEvent.HitEventID,
FireEvent.AssociatedPlayerID,
--HitEvent.AssociatedPlayerID,
FireEvent.EventTime,
HitEvent.EventTime [HitEventTime],
FireEvent.Longitude [FireEventLongitute],
FireEvent.Latitude [FireEventLatitute],
HitEvent.Longitude [HitEventLongitute],
HitEvent.Latitude [HitEventLatitute],
HitEvent.HitResult ,
FireEvent.AmmunitionCode,
FireEvent.AmmunitionSource,
0 [IsArtillery],
RANK() OVER(PARTITION BY HitEvent.FireEventID, HitEvent.FiringPlayerID, HitEvent.AmmunitionCode,HitEvent.ExerciseID ORDER BY HitEvent.EventTime) [RankValue]
FROM FireEvent
LEFT JOIN HitEvent
ON HitEvent.FireEventID = FireEvent.FireEventID
AND 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 = FireEvent.ExerciseID
AND HitEvent.HitResult NOT IN ( 0, 1 )
) data
WHERE RanKValue = 1
与使用外部应用
相比,这可能会稍微提高性能,但可能不会。这取决于您的模式和正在处理的数据量。测试是无法替代的:使用而不是左连接。我不得不把你们的一些条款移走,但下面的内容应该会产生预期的结果
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
OUTER APPLY
( SELECT HitEvent.*, RANK() OVER (ORDER BY HitEvent.EventTime) AS RankValue
FROM HitEvent
WHERE HitEvent.FireEventID = FireEvent.FireEventID
AND 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 = FireEvent.ExerciseID
AND HitEvent.HitResult NOT IN ( 0, 1 )
) AS tempHitEvent
WHERE COALESCE(RankValue, 1) = 1
AND FireEvent.ExerciseID = 'D289D508-1479-4C17-988C-5F6A847AE51E'
ORDER BY FireEvent.HitEventID
如果您只想在存在匹配的HitEvent的情况下返回结果,请使用交叉应用
<代码>交叉应用是到外部应用
什么内部连接
是到左侧连接
附录 这一切都可以通过使用联接来实现,而无需使用
OUTER APPLY
,方法是不使用子查询来联接HitEvent,然后对所有数据执行RANK
函数,而不仅仅是HitEvent表。所有这些都需要移动到子查询中,以便RANK
函数的结果可以包含在WHERE
子句中
SELECT *
FROM ( SELECT FireEvent.ExerciseID,
FireEvent.FireEventID,
HitEvent.HitEventID,
FireEvent.AssociatedPlayerID,
--HitEvent.AssociatedPlayerID,
FireEvent.EventTime,
HitEvent.EventTime [HitEventTime],
FireEvent.Longitude [FireEventLongitute],
FireEvent.Latitude [FireEventLatitute],
HitEvent.Longitude [HitEventLongitute],
HitEvent.Latitude [HitEventLatitute],
HitEvent.HitResult ,
FireEvent.AmmunitionCode,
FireEvent.AmmunitionSource,
0 [IsArtillery],
RANK() OVER(PARTITION BY HitEvent.FireEventID, HitEvent.FiringPlayerID, HitEvent.AmmunitionCode,HitEvent.ExerciseID ORDER BY HitEvent.EventTime) [RankValue]
FROM FireEvent
LEFT JOIN HitEvent
ON HitEvent.FireEventID = FireEvent.FireEventID
AND 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 = FireEvent.ExerciseID
AND HitEvent.HitResult NOT IN ( 0, 1 )
) data
WHERE RanKValue = 1
与使用
外部应用
相比,这可能会稍微提高性能,但可能不会。这取决于您的模式和正在处理的数据量。测试是无法替代的:这不起作用,通过应用子查询中的条件,选择RANK
函数的结果。i、 e.通过使用外部应用,子查询将返回fireevent.EventTime的5秒钟内的第一个事件,但是,如果第一个HitEvent在fireevent时间的5秒钟内,则您的查询将只返回结果(存在细微但重要的差异)。我修改了查询,以便在rank()中使用更好的分区子句。这并不完全相同。但是,我认为您可以展开查询,只需获取子查询,添加另一列(使用窗口函数)来计算fire事件id,并完全取消外部连接。修改partion子句在一定程度上有所帮助,然而,一个基本问题仍然存在,即子查询的结果与主查询直接相关,因此需要相关子查询。为了更好地演示这个问题,我做了一个实验。在第二个结果窗格中,HitResult为空,因为第一个HitEvent不在FireEvent的5秒内。在top查询中,将显示5秒内的第一个HitEvent(HitResult=4,因为这发生在HitResult=5的行之前)。在窗口函数出现之前,所有相关子查询都可以编写为联接和分组。您的意思是需要在子查询中连接到FE。如果其中一个“应用”方法不起作用,您可以将其添加回。我并不是说使用相关子查询是唯一的方法,我要说的是,您发布的查询与问题中提出的逻辑(即fireevent 5秒内的第一个hitevent)的工作方式不同。这不起作用,通过应用子查询中的条件,选择RANK
函数的结果。i、 e.通过使用外部应用,子查询将返回fireevent.EventTime的5秒钟内的第一个事件,但是,如果第一个HitEvent在fireevent时间的5秒钟内,则您的查询将只返回结果(存在细微但重要的差异)。我修改了查询,以便在rank()中使用更好的分区子句。这并不完全相同。但是,我认为您可以展开查询,只需获取子查询,添加另一列(使用窗口函数)来计算fire事件id,并完全取消外部连接。修改partion子句在一定程度上有所帮助,然而,一个基本问题仍然存在,即子查询的结果与主查询直接相关,因此需要相关子查询。为了更好地演示这个问题,我做了一个实验。在第二个结果窗格中,HitResult为空,因为第一个HitEvent不在FireEvent的5秒内。在顶部查询中,将显示5秒内的第一个HitEvent(带HitResult)