use*_*279 3 t-sql sql-server geospatial sqlgeography sqlgeometry
这里也提出了类似的问题:
进一步提出这个问题,我有一个如下所示的表模式:
CREATE TABLE [dbo].[LongAndLats](
[Longitude] [float] NULL,
[Latitude] [float] NULL,
[SortOrder] [bigint] NULL,
[SensorID] [bigint] NULL,
)
Run Code Online (Sandbox Code Playgroud)
示例数据如下所示:
如何使用TSQL 将这些点转换为每个SensorID的地理折线(以便我为每个SensorID设置SensorID/Polyline记录)?
我尝试过使用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
Run Code Online (Sandbox Code Playgroud)
结果如下:
最后,我想要一个返回所有SensorID/Polyline对的视图.我不知道我目前的做法是否有效.我将不胜感激任何建议或例子.
从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;
Run Code Online (Sandbox Code Playgroud)
我尝试过使用db_cursor但是我为每个组获得了一个单独的结果集
请避免使用游标,以分号结束每一行并停止使用:
SELECT @BuildString = COALESCE(@BuildString + ',', '')
+ CAST([Longitude] AS NVARCHAR(50)) + ' ' + CAST([Latitude]
AS NVARCHAR(50))
FROM [LongAndLats]
WHERE SensorID = @SensorID
ORDER BY SortOrder;
Run Code Online (Sandbox Code Playgroud)
上面的构造可能看起来不错,但它可能导致未定义的行为.更多信息:nvarchar concatenation/index/nvarchar(max)莫名其妙的行为
编辑:
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;
Run Code Online (Sandbox Code Playgroud)
EDIT2:
避免:
执行用户定义的例程或聚合"地理"期间发生.NET Framework错误:
System.FormatException:24117:LineString输入无效,因为它没有足够的点.LineString必须至少有两个点.
你可以添加HAVING COUNT(*) > 1;
最终编辑:
如果您有"垃圾数据",只需将其过滤掉(或CHECK在该列上添加约束):
"纬度值必须介于-90到90度之间"
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;
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
546 次 |
| 最近记录: |