Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 如何使用带有Lat Longs的表格类型进行批处理?_Sql Server_Tsql_Stored Procedures_Geospatial_Spatial - Fatal编程技术网

Sql server 如何使用带有Lat Longs的表格类型进行批处理?

Sql server 如何使用带有Lat Longs的表格类型进行批处理?,sql-server,tsql,stored-procedures,geospatial,spatial,Sql Server,Tsql,Stored Procedures,Geospatial,Spatial,我试图将表类型传递到存储过程中,希望存储过程查找每一行的lat/long,并将该行最近的点返回给我 类型: 存储过程: ALTER PROCEDURE [dbo].[BatchNearestRoadNodes] @Input dbo.LatLongRoadLinkType READONLY AS BEGIN -- do stuff here -- return a table of id from input, nodeid and distance END 它需要对

我试图将表类型传递到存储过程中,希望存储过程查找每一行的lat/long,并将该行最近的点返回给我

类型:

存储过程:

ALTER PROCEDURE [dbo].[BatchNearestRoadNodes]
    @Input dbo.LatLongRoadLinkType READONLY
AS
BEGIN
    -- do stuff here
    -- return a table of id from input, nodeid and distance 
END
它需要对整个表执行单个lat/long的操作:

DECLARE @g geography = 'POINT(13.5333414077759 54.549524307251)';
DECLARE @region geography = @g.STBuffer(5000)

SELECT TOP 1 NodeID, Point.STDistance(@g) as 'Distance'
FROM Location 
WHERE Point.Filter(@region) = 1
ORDER BY Point.STDistance(@g)
Location表具有类型为Geography的重要列点,该列点在空间上被索引,并且是进行比较的对象。我正在将代码中的lat/longs表发送到存储过程中,代码期望返回:

Id (original point passed in)
NodeID (of nearest point in location table)
Distance
我应该如何处理这个问题?为了使它更简单一些,我可以简单地将SqlGeography从代码传递到存储过程中,而不是Lat/Long,但是这会降低性能,因为转换成它非常昂贵

编辑: 这是可行的,但我不知道这是否是最佳解决方案

性能-V1 vs Jon的编辑


差别很小。需要将最后一个数字降下来。

尝试以下方法以获得部分结果:

WITH PreQuery AS
(
I.Id,
GEOGRAPHY::STPointFromText(I.PointAsWKT).STBuffer(5000) AS Geog,
L.NodeId,
L.Point
FROM
@Input AS I
JOIN
Location AS L ON L.Point.STIntersects(I.Geog) = 1
)
SELECT
P.Id,
P.NodeId,
P.Geog.STDistance(P.Point) AS Distance
FROM
PreQuery P
我已经从头开始写了它,没有任何测试数据,所以可能会有小错误,但主要是它会给你每个节点,它的距离在5000米以内的每个点。您仍然需要对它们进行过滤,以便只获得每个id之间距离最小的一个id,这不太难-

希望它能有所帮助,即使不完整

编辑12月2日

我已经看到了我的第一个解决方案的问题,你无法得到距离,因为它是预缓冲的,用于记录主要内容。然而,这种合并应该是两种尝试的最有效组合

WITH PreQuery AS
(
SELECT
I.Id,
geography::Point(I.Latitude, I.Longitude, 4326) AS InputGeography
FROM
@input AS I
)
SELECT x.Id, x.LocationName, x.NodeId, x.Distance
FROM
(
SELECT
PQ.Id,
L.LocationName,
L.NodeId,
L.Point.STDistance(PQ.InputGeography) AS Distance,
ROWNUMBER() OVER (PARTITION BY I.Id ORDER BY L.Point.Distance(PQ.InputGeography) ASC) AS Ranking
FROM
Prequery AS PQ
JOIN
Location AS L
-- ON L.Point.STIntersects(PQ.InputGeography.STBuffer(5000)) = 1 -- Slower
ON L.Point.STDistance(PQ.InputGeography) <= 5000 -- Faster
) AS X WHERE Ranking = 1

这样,您只需预创建一次输入地理信息,而不是按照您的尝试预创建三次。同样,这是未经测试的,但应该证明是最有效的。

如果您想利用空间索引,您必须在某个时候无论如何转换为SqlGeography。无论您是以float/float的形式传递它,然后转换它,还是仅以SqlGeography的形式传递它,您都必须转换它。除非你的表中有大量的数字,否则开销并不是那么糟糕。您正在运行哪个版本的SQL?@Muhammed。看起来不错,很高兴我的给了一些依据。我要说的唯一一件事是,您在查询中转换了两次地理信息。考虑使用子查询/CTE,我首先计算地理实例一次,然后再使用它。行数是多少?没问题,全部完成。我真的很喜欢你的号码。。。解决方案出于某种原因,我没有考虑过它,但它很有效。答案更新如下。希望这一次能起作用,地理信息只转换一次,而不是三次。将节省一些女士。让我知道它是如何改进的。嗨,乔恩,请在我的编辑中查看性能结果。试图找到一种提高准确性和速度的方法。也许递归方法会奏效,比如,缓冲区越小,点数越少,越大。我不相信递归方法会奏效,因为你必须处理多个调用和每个级别的过滤。尝试将连接更改为L.Point.STDistancePQ.InputGeography是的,这有改进,现在最后一个是14475毫秒:我将编辑您的答案以添加V3。
V1
============
original:643 found:627 in:1361 ms
original:1018 found:999 in:1700 ms
original:1801 found:1758 in:2628 ms
original:4098 found:3973 in:5271 ms
original:16388 found:15948 in:19624 ms

Jon's Edit
==========
original:643 found:627 in:1333 ms
original:1018 found:999 in:1689 ms
original:1801 found:1758 in:2559 ms
original:4098 found:3973 in:5114 ms
original:16388 found:15948 in:19054 ms
WITH PreQuery AS
(
I.Id,
GEOGRAPHY::STPointFromText(I.PointAsWKT).STBuffer(5000) AS Geog,
L.NodeId,
L.Point
FROM
@Input AS I
JOIN
Location AS L ON L.Point.STIntersects(I.Geog) = 1
)
SELECT
P.Id,
P.NodeId,
P.Geog.STDistance(P.Point) AS Distance
FROM
PreQuery P
WITH PreQuery AS
(
SELECT
I.Id,
geography::Point(I.Latitude, I.Longitude, 4326) AS InputGeography
FROM
@input AS I
)
SELECT x.Id, x.LocationName, x.NodeId, x.Distance
FROM
(
SELECT
PQ.Id,
L.LocationName,
L.NodeId,
L.Point.STDistance(PQ.InputGeography) AS Distance,
ROWNUMBER() OVER (PARTITION BY I.Id ORDER BY L.Point.Distance(PQ.InputGeography) ASC) AS Ranking
FROM
Prequery AS PQ
JOIN
Location AS L
-- ON L.Point.STIntersects(PQ.InputGeography.STBuffer(5000)) = 1 -- Slower
ON L.Point.STDistance(PQ.InputGeography) <= 5000 -- Faster
) AS X WHERE Ranking = 1