按值分组并从 T-SQL 中的每个组的点(纬度和经度)创建地理折线
Group by value and create geography polyline from points (latitude and longitude) for each group in T-SQL
这里有人问过类似的问题:
Create geography polyline from points in T-SQL
进一步研究这个问题,我有一个 table 架构,如下所示:
CREATE TABLE [dbo].[LongAndLats](
[Longitude] [float] NULL,
[Latitude] [float] NULL,
[SortOrder] [bigint] NULL,
[SensorID] [bigint] NULL,
)
示例数据如下所示:
如何使用 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
结果:
最终,我想要一个返回所有 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;
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服务器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;
编辑2:
避免:
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
;
最终编辑:
如果您有 "garbage data",只需将其过滤掉(或对该列添加 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;
这里有人问过类似的问题:
Create geography polyline from points in T-SQL
进一步研究这个问题,我有一个 table 架构,如下所示:
CREATE TABLE [dbo].[LongAndLats](
[Longitude] [float] NULL,
[Latitude] [float] NULL,
[SortOrder] [bigint] NULL,
[SensorID] [bigint] NULL,
)
示例数据如下所示:
如何使用 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
结果:
最终,我想要一个返回所有 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;
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服务器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;
编辑2:
避免:
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
;
最终编辑:
如果您有 "garbage data",只需将其过滤掉(或对该列添加 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;