Sql server 2008 r2 具有多个坐标的SQL Linestring-我可以使用每个位置进行距离计算吗?
我正在尝试确定是否可以使用具有多个坐标的LineString,并计算LineString中每个项目与另一个具有坐标的表之间的距离: 我有几个地方需要参观,例如:Sql server 2008 r2 具有多个坐标的SQL Linestring-我可以使用每个位置进行距离计算吗?,sql-server-2008-r2,spatial,Sql Server 2008 R2,Spatial,我正在尝试确定是否可以使用具有多个坐标的LineString,并计算LineString中每个项目与另一个具有坐标的表之间的距离: 我有几个地方需要参观,例如: A1 40.7120879 -73.9113197 A2 40.7828647 -73.9653551 A3 40.740777 -73.841136 我想找出这些线串位置和我将停在的其他位置之间的距离 B1 40.7029334,-73.6208314 B2 40.7037142,-73.6086649 B3 4
A1 40.7120879 -73.9113197
A2 40.7828647 -73.9653551
A3 40.740777 -73.841136
我想找出这些线串位置和我将停在的其他位置之间的距离
B1 40.7029334,-73.6208314
B2 40.7037142,-73.6086649
B3 40.7088981,-73.6137852
B4 40.7133267,-73.6056991
B5 40.7185586,-73.6007205
e、 g
等
至少我知道这没有内置函数,但是类似的东西应该会给你你想要的结果
--Index of point on linestring
DECLARE @i INT = 1
--Output
DECLARE @ResultTable TABLE (LinePointNumber INT, PointID INT, Distance FLOAT)
--Identifier for the individual points
DECLARE @id INT
DECLARE @g GEOGRAPHY
--Linestring
DECLARE @geogcol GEOGRAPHY = (SELECT TOP 1 GeogCol1 FROM SpatialTable)
--loop through each point on the linestring
WHILE @i <= @geogcol.STNumPoints()
BEGIN
--turn points into geography and loop through the collection
--if you just cast a float to a varchar it will truncate, so cast to a decimal first to prevent that
DECLARE pointcursor CURSOR FOR SELECT id, GEOGRAPHY::STPointFromText('POINT(' + CAST(CAST(Longitude AS DECIMAL(15,10)) AS VARCHAR(15)) + ' ' + CAST(CAST(Latitude AS DECIMAL(15,10)) AS VARCHAR(15)) + ')', 4326)
OPEN pointcursor
FETCH NEXT FROM pointcursor INTO @id, @g
WHILE @@FETCH_STATUS = 0
BEGIN
--STPointN returns that point, the the distance is STDistance
INSERT INTO @ResultTable (LinePointNumber, PointID, Distance) VALUES (@i, @id, @g.STDistance(@geogcol.STPointN(@i)))
FETCH NEXT FROM pointcursor INTO @id, @g
END
CLOSE pointcursor
DEALLOCATE pointcursor
SET @i = @i + 1
END
SELECT * FROM @ResultTable
Hcaelxxam刚刚击败我找到了一个解决方案——并且是本机SQL。无论如何,我已经为你准备好了,就在这里 给定一个
public class MyPoint
{
public MyPoint(string title, SqlGeography location)
{
this.Title = title;
this.Location = location;
}
public string Title { get; set; }
public SqlGeography Location { get; set; }
}
使用以下代码:
// The line, or route consisting of "waypoints"
SqlGeography lineString = SqlGeography.STLineFromText(new System.Data.SqlTypes.SqlChars("LINESTRING(40.7120879 -73.9113197, 40.7828647 -73.9653551, 40.740777 -73.841136)"), 4326);
// A container for all lookups
List<MyPoint> stopLocations = new List<MyPoint>();
// A container for all waypoints in the route
List<MyPoint> wayPoints = new List<MyPoint>();
// Add the stop locations
stopLocations.Add(new MyPoint("B1", SqlGeography.Point(-73.6208314, 40.7029334, 4326)));
stopLocations.Add(new MyPoint("B2", SqlGeography.Point(-73.6086649, 40.7037142, 4326)));
stopLocations.Add(new MyPoint("B3", SqlGeography.Point(-73.6137852, 40.7088981, 4326)));
stopLocations.Add(new MyPoint("B4", SqlGeography.Point(-73.6056991, 40.7133267, 4326)));
stopLocations.Add(new MyPoint("B5", SqlGeography.Point(-73.6007205, 40.7185586, 4326)));
// Add the waypoints
for (int i = 1; i < (lineString.STNumPoints() + 1); i++)
{
wayPoints.Add(new MyPoint("A" + i, SqlGeography.Point(lineString.STPointN(i).Lat.Value, lineString.STPointN(i).Long.Value, lineString.STSrid.Value)));
}
// Join the data (essentially a cross-join) and calculate distances
var joinAndCalculate = (
from wp in wayPoints
from sl in stopLocations
select new
{
WayPointTitle = wp.Title,
StopLocationTitle = sl.Title,
DistanceInMetres = wp.Location.STDistance(sl.Location)
}
).OrderBy(x => x.WayPointTitle).ThenBy(x => x.StopLocationTitle)
.ToList()
;
// Print to the console, for testing
foreach (var data in joinAndCalculate)
{
Console.WriteLine(data.WayPointTitle + "\t" + data.StopLocationTitle + "\t" + data.DistanceInMetres);
}
如果不是你,它可能会帮助其他人。它必须是SQL语言,还是你能用c语言回答?在这一点上,我很绝望,所以c会做的:这是非常酷的人,我从来没有在c语言中使用过这个东西,所以看到它这样使用是非常酷的。如果你不介意的话,我有几个问题要问;第一个问题是,当您添加指向STPointN1而不是STPointNi的航路点时,这只是一个错误,还是我误解了您的做法?我的另一个问题是,你知道把这样的东西变成CLR函数有多难吗?我从来没有这样做过,但这似乎是一个完美的用法。@hcaelxxam一点问题也没有。感谢您注意到,应该是i而不是1,所以我已经更新了代码!您必须从1开始,因为所有地理方法都是基于1的索引。从理论上讲,它作为CLR函数实现应该不会太难。我从未尝试过,总是更喜欢使用SQL作为数据存储,并尽可能用c实现业务需求/逻辑。在OP的情况下,如果在SQL direct中首选该解决方案,CLR实际上可能会工作得更好。@hcaelxxam如果您可以实现为CLR函数,我应该补充一点,它可能会提高性能。从性能的角度来看,SQL讨厌游标,但是如果不在SQL之外实现,就很难在没有游标的情况下实现OP想要的东西。感谢您的回复。我一直在做一个ETL过程,其中包括一些与OP非常相似的东西,我必须到处使用游标。如果弄清楚如何在C语言中实现这一点,现在就能提高性能,那么处理所有待办事项数据似乎需要一个多星期的时间,我肯定需要研究一下。一点问题也没有。喜欢这张照片,让我想起了你在老电影中看到的一座非常古老的索桥研究CLR函数绝对值得一试。SQL的强大之处在于它可以处理大型集合,我相信您知道这一点,因此,将其从设计时没有考虑的更为平凡的东西中解放出来,基本上可以提高性能。
public class MyPoint
{
public MyPoint(string title, SqlGeography location)
{
this.Title = title;
this.Location = location;
}
public string Title { get; set; }
public SqlGeography Location { get; set; }
}
// The line, or route consisting of "waypoints"
SqlGeography lineString = SqlGeography.STLineFromText(new System.Data.SqlTypes.SqlChars("LINESTRING(40.7120879 -73.9113197, 40.7828647 -73.9653551, 40.740777 -73.841136)"), 4326);
// A container for all lookups
List<MyPoint> stopLocations = new List<MyPoint>();
// A container for all waypoints in the route
List<MyPoint> wayPoints = new List<MyPoint>();
// Add the stop locations
stopLocations.Add(new MyPoint("B1", SqlGeography.Point(-73.6208314, 40.7029334, 4326)));
stopLocations.Add(new MyPoint("B2", SqlGeography.Point(-73.6086649, 40.7037142, 4326)));
stopLocations.Add(new MyPoint("B3", SqlGeography.Point(-73.6137852, 40.7088981, 4326)));
stopLocations.Add(new MyPoint("B4", SqlGeography.Point(-73.6056991, 40.7133267, 4326)));
stopLocations.Add(new MyPoint("B5", SqlGeography.Point(-73.6007205, 40.7185586, 4326)));
// Add the waypoints
for (int i = 1; i < (lineString.STNumPoints() + 1); i++)
{
wayPoints.Add(new MyPoint("A" + i, SqlGeography.Point(lineString.STPointN(i).Lat.Value, lineString.STPointN(i).Long.Value, lineString.STSrid.Value)));
}
// Join the data (essentially a cross-join) and calculate distances
var joinAndCalculate = (
from wp in wayPoints
from sl in stopLocations
select new
{
WayPointTitle = wp.Title,
StopLocationTitle = sl.Title,
DistanceInMetres = wp.Location.STDistance(sl.Location)
}
).OrderBy(x => x.WayPointTitle).ThenBy(x => x.StopLocationTitle)
.ToList()
;
// Print to the console, for testing
foreach (var data in joinAndCalculate)
{
Console.WriteLine(data.WayPointTitle + "\t" + data.StopLocationTitle + "\t" + data.DistanceInMetres);
}