Sql server 2008 r2 具有多个坐标的SQL 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

我正在尝试确定是否可以使用具有多个坐标的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 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);
        }