sql-server - 按值分组并从 T-SQL 中的每个组的点(纬度和经度)创建地理折线

标签 sql-server tsql geospatial sqlgeography sqlgeometry

这里有人问过类似的问题:

Create geography polyline from points in T-SQL

进一步考虑这个问题,我有一个如下所示的表模式:

CREATE TABLE [dbo].[LongAndLats](
[Longitude] [float] NULL,
[Latitude] [float] NULL,
[SortOrder] [bigint] NULL,
[SensorID] [bigint] NULL,
)

示例数据如下所示:

enter image description here

如何使用 TSQL 将这些点转换为每个 SensorID 的地理多段线(以便每个 SensorID 都有一个 SensorID/多段线记录)?

我试过使用 db_cursor,但我得到了每个组的单独结果集(我认为地理位置可能相同)。这段代码:

DECLARE @SensorID VARCHAR(2000)
DECLARE @LineFromPoints geography
DECLARE @BuildString NVARCHAR(MAX)

DECLARE db_cursor CURSOR FOR  
SELECT Distinct([SensorId]) 
FROM [dbo].[LongAndLats]

OPEN db_cursor   
FETCH NEXT FROM db_cursor INTO LongAndLats 

WHILE @@FETCH_STATUS = 0   
BEGIN   
       SELECT @BuildString = COALESCE(@BuildString + ',', '') + CAST([Longitude] AS NVARCHAR(50)) + ' ' + CAST([Latitude] AS NVARCHAR(50))
       FROM [LongAndLats]
       WHERE SensorID = @SensorID
       ORDER BY SortOrder            

       SET @BuildString = 'LINESTRING(' + @BuildString + ')';   
       SET @LineFromPoints = geography::STLineFromText(@BuildString, 4326);
       SELECT @LineFromPoints As 'Geomerty', @name As 'SensorID' 

       FETCH NEXT FROM db_cursor INTO @name   
END   

CLOSE db_cursor   
DEALLOCATE db_cursor

结果:

enter image description here

最终,我想要一个返回所有 SensorID/Polyline 对的 View 。我不知道我目前的方法是否有效。我将不胜感激任何建议或例子。

最佳答案

SQL Server 2017+ 你可以使用:

SELECT geography::STLineFromText('LINESTRING(' + 
         STRING_AGG(CONCAT(Longitude, ' ' ,Latitude), ',') 
         WITHIN GROUP(ORDER BY SortOrder) + ')' , 4326) AS geometry
      ,SensorId
FROM dbo.LongAndLats
GROUP BY SensorId
HAVING COUNT(*) > 1;

DBFiddle Demo


I've tried using a db_cursor but I get a separate result set for each group

请避免使用光标,每行以分号结束并停止使用:

SELECT @BuildString = COALESCE(@BuildString + ',', '') 
       + CAST([Longitude] AS NVARCHAR(50)) + ' ' + CAST([Latitude] 
        AS NVARCHAR(50))
FROM [LongAndLats]
WHERE SensorID = @SensorID
ORDER BY SortOrder;  

上面的构造可能看起来不错,但它可能导致未定义的行为。更多信息:nvarchar concatenation / index / nvarchar(max) inexplicable behavior

编辑:

SQL Server 2012 版本:

SELECT geography::STLineFromText('LINESTRING(' 
      + STUFF(
             (SELECT ',' + CONCAT(Longitude, ' ' ,Latitude) 
              FROM dbo.LongAndLats t2
              WHERE t1.SensorId = t2.SensorId 
              ORDER BY SortOrder
              FOR XML PATH (''))
             , 1, 1, '')
       + ')' 
       , 4326) AS geometry, SensorId
FROM dbo.LongAndLats t1
GROUP BY SensorId
HAVING COUNT(*) > 1;

DBFiddle Demo2

EDIT2:

避免:

A .NET Framework error occurred during execution of user-defined routine or aggregate "geography":

System.FormatException: 24117: The LineString input is not valid because it does not have enough points. A LineString must have at least two points.

你可以添加 HAVING COUNT(*) > 1;

最终编辑:

如果您有“垃圾数据”,只需将其过滤掉(或在该列上添加 CHECK 约束):

"Latitude values must be between -90 and 90 degrees"

SELECT geography::STLineFromText('LINESTRING(' 
      + STUFF(
             (SELECT ',' + CONCAT(Longitude, ' ' ,Latitude) 
              FROM dbo.LongAndLats t2
              WHERE t1.SensorId = t2.SensorId 
                AND Latitude BETWEEN -90 and 90
                AND Longitude BETWEEN -180 AND 180
              ORDER BY SortOrder
              FOR XML PATH (''))
             , 1, 1, '')
       + ')' 
       , 4326) AS geometry, SensorId
FROM dbo.LongAndLats t1
WHERE Latitude BETWEEN -90 and 90
  AND Longitude BETWEEN -180 AND 180
GROUP BY SensorId
HAVING COUNT(*) > 1;

DBFiddle Demo3

关于sql-server - 按值分组并从 T-SQL 中的每个组的点(纬度和经度)创建地理折线,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48241483/

相关文章:

sql - 每月获取新数据

mysql - 匹配最近的经度/纬度

javascript - D3.geo.bounds 不返回边界框?

c# - 不同提供商的相同 EDMX 文件

c# - 1 个对执行 3 件事的存储过程的异步调用与 3 个对执行一件事的存储过程的异步调用?

SQL - 使用适用于多行的 WHERE 进行选择

sql - 上个月的最后一天 - BigQuery

SQL 查询 - 从两个不同级别的层次结构中获取总和

r - 考虑空间自相关的 2 个栅格之间的相关性

sql - 临时表列大小在多少行之后确定?