将字符串和 select 拆分为新的 table
Split string and select into new table
我有一个 table 具有这样的结构
ID pointCount pointSeries
1 282 35.1079,-111.0151,35.1088,-111.0196...
显然点系列是字符串,有一对经纬度作为点。我想 select 将 pointSeries 变成一个新的 table
ID Lat Lon
1 35.1079 -111.0151
1 35.1088 -111.0196
我可以进行拆分并 select 进入查询的最佳方式是什么?
您需要一个将逗号分隔的字符串拆分成单独行的函数。这是 Jeff Moden 的 DelimitedSplit8K 函数。
CREATE FUNCTION [dbo].[DelimitedSplit8K](
@pString NVARCHAR(4000), @pDelimiter NCHAR(1)
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,E2(N) AS (SELECT 1 FROM E1 a, E1 b)
,E4(N) AS (SELECT 1 FROM E2 a, E2 b)
,cteTally(N) AS(
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
,cteStart(N1) AS(
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(
SELECT
s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
然后你需要对拆分的结果进行透视以获得所需的结果:
;WITH CteSplitted AS(
SELECT
t.ID,
x.ItemNumber,
Item = CAST(x.Item AS NUMERIC(16,4)),
RN = (ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ItemNumber) + 1) / 2
FROM Test t
CROSS APPLY dbo.DelimitedSplit8K(t.PointSeries, ',') x
)
SELECT
ID,
Lat = MAX(CASE WHEN ItemNumber % 2 = 1 THEN Item END),
Lon = MAX(CASE WHEN ItemNumber % 2 = 0 THEN Item END)
FROM CteSplitted
GROUP BY ID, RN
我有一个 table 具有这样的结构
ID pointCount pointSeries
1 282 35.1079,-111.0151,35.1088,-111.0196...
显然点系列是字符串,有一对经纬度作为点。我想 select 将 pointSeries 变成一个新的 table
ID Lat Lon
1 35.1079 -111.0151
1 35.1088 -111.0196
我可以进行拆分并 select 进入查询的最佳方式是什么?
您需要一个将逗号分隔的字符串拆分成单独行的函数。这是 Jeff Moden 的 DelimitedSplit8K 函数。
CREATE FUNCTION [dbo].[DelimitedSplit8K](
@pString NVARCHAR(4000), @pDelimiter NCHAR(1)
)
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
)
,E2(N) AS (SELECT 1 FROM E1 a, E1 b)
,E4(N) AS (SELECT 1 FROM E2 a, E2 b)
,cteTally(N) AS(
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
,cteStart(N1) AS(
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(
SELECT
s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
SELECT
ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
然后你需要对拆分的结果进行透视以获得所需的结果:
;WITH CteSplitted AS(
SELECT
t.ID,
x.ItemNumber,
Item = CAST(x.Item AS NUMERIC(16,4)),
RN = (ROW_NUMBER() OVER(PARTITION BY ID ORDER BY ItemNumber) + 1) / 2
FROM Test t
CROSS APPLY dbo.DelimitedSplit8K(t.PointSeries, ',') x
)
SELECT
ID,
Lat = MAX(CASE WHEN ItemNumber % 2 = 1 THEN Item END),
Lon = MAX(CASE WHEN ItemNumber % 2 = 0 THEN Item END)
FROM CteSplitted
GROUP BY ID, RN