假设我在SQL Server 2012上运行此查询
SELECT Coordinates
FROM Table
我得到了这个结果:
TextA,TextB,TextC,TextD,TextE,TextF
我想要的是解析这个结果并获得以下结果:
TextA,TextB;TextC,TextD;TextE,TextF
也就是说,每对后面都有一个分号。
有可能实现这一目标吗?
答案 0 :(得分:1)
编辑1:我刚注意到结果的最后一行有问题(它也是一个X),现在尝试解决这个问题。
编辑2:修复了编辑1中的错误
此查询为您提供了一个函数,可以像这样结果分割您的输入字符串:
select * from dbo.Split('123,456,789,000', ',')
Nr Typ Value
1 X 123
1 Y 456
2 X 789
2 Y 000
功能码:
CREATE FUNCTION Split (
@InputString VARCHAR(5000),
@Delimiter VARCHAR(50)
)
RETURNS @Items TABLE (
Nr INT,
Typ VARCHAR(50),
Value VARCHAR(MAX)
)
AS
BEGIN
IF @Delimiter = ' '
BEGIN
SET @Delimiter = ','
SET @InputString = REPLACE(@InputString, ' ', @Delimiter)
END
IF (@Delimiter IS NULL OR @Delimiter = '')
SET @Delimiter = ','
DECLARE @Item VARCHAR(5000)
DECLARE @ItemList VARCHAR(5000)
DECLARE @Typ VARCHAR(50)
DECLARE @DelimIndex INT
DECLARE @RowNumber INT
SET @ItemList = @InputString
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
SET @Typ = 'Y' -- the typ for the coordinates, also the indicator for @RowNumber
SET @RowNumber = 0 -- each pair gets their own rownumber
WHILE (@DelimIndex != 0)
BEGIN
SET @Item = SUBSTRING(@ItemList, 0, @DelimIndex)
SET @Typ = (CASE WHEN @Typ = 'Y' THEN 'X' ELSE 'Y' END)
SET @RowNumber = @RowNumber + (CASE WHEN @Typ = 'X' THEN 1 ELSE 0 END)
INSERT INTO @Items VALUES (@RowNumber, @Typ, @Item)
SET @ItemList = SUBSTRING(@ItemList, @DelimIndex+1, LEN(@ItemList)-@DelimIndex)
SET @DelimIndex = CHARINDEX(@Delimiter, @ItemList, 0)
END
IF @Item IS NOT NULL -- if at least 1 delimiter was encountered in @InputString
BEGIN
SET @Item = @ItemList
INSERT INTO @Items VALUES (@RowNumber + 1, (CASE WHEN @Typ = 'Y' THEN 'X' ELSE 'Y' END), @Item)
END
-- if 0 delimiters where found it just returns the default @InputString
ELSE
INSERT INTO @Items VALUES (@RowNumber + 1, @Typ, @InputString)
RETURN
END
GO
答案 1 :(得分:1)
使用递归CTE,您可以快速轻松地完成此任务:
WITH Tab AS(
SELECT ID = 1
, Coordinates = 'TexasdasdtA,TextB,TextC,TexsdsdstD,TextE,TextF'
, AnotherCol = 'Bla'
),
ParseCoordinates AS(
SELECT
ID
, result = CAST('' AS VARCHAR(MAX))
, remaining = Tab.Coordinates
FROM Tab
UNION ALL
SELECT
ID
, result = result +';'+ NextPart.Value
, remaining = SUBSTRING(remaining, LEN(NextPart.Value)+2, LEN(remaining))
FROM ParseCoordinates
CROSS APPLY(
SELECT Value = SUBSTRING(remaining, 1, ISNULL(NULLIF(CHARINDEX(',',remaining, CHARINDEX(',',remaining)+1)-1, -1), LEN(remaining)))
) AS NextPart
WHERE remaining <> ''
)
SELECT T.ID
, Coordinates = SUBSTRING(result, 2, LEN(result))
, AnotherCol
FROM Tab AS T
INNER JOIN ParseCoordinates AS PS
ON T.ID = PS.ID
WHERE remaining = ''
编辑:根据列的数量,A)通过CTE传递它们或B)仅通过CTE传递一个键,并将原始选项卡连接到具有解析值的CTE。
答案 2 :(得分:0)
这会做你想要的事情:
CREATE TABLE TestTable (Label varchar(20));
INSERT INTO TestTable (Label)
VALUES ('TextA'), ('TextB'), ('TextC'), ('TextD'), ('TextE'), ('TextF');
DECLARE @flag bit;
DECLARE @result varchar(MAX);
SET @flag = 0;
SET @result = '';
SELECT @result += Label + CASE WHEN @flag = 0 THEN ',' ELSE ';' END, @flag = ~@flag
FROM TestTable;
SELECT @result;
答案 3 :(得分:0)
创建此功能以对坐标进行分组。该功能已根据here进行了调整,其功能可根据您的要求进行扩展。
CREATE FUNCTION [dbo].[udf_CoordinatesGrouper] (
@List VARCHAR(max)
,@delimiter VARCHAR(10)
)
RETURNS @ReturnValue TABLE (col VARCHAR(8000))
AS
BEGIN
DECLARE @Values TABLE (
ID INT IDENTITY(1, 1)
,col VARCHAR(8000)
)
IF @List IS NULL
OR LEN(@List) = 0
RETURN;
SET @List = replace(@List, CHAR(39) + CHAR(39), CHAR(39))
DECLARE @Index INT = 1;
DECLARE @ItemValue VARCHAR(100);
DECLARE @pos INT = 1;
DECLARE @l INT = LEN(@List);
WHILE @Index > 0
BEGIN
SET @Index = CHARINDEX(@Delimiter, @List, @pos);
IF @Index > 0
IF (@index - @pos > 0)
SET @ItemValue = SUBSTRING(@List, @pos, @index - @pos);
ELSE
SET @ItemValue = NULL;
ELSE IF (@l - @pos + 1) > 0
SET @ItemValue = SUBSTRING(@List, @pos, @l - @pos + 1);
ELSE
SET @ItemValue = NULL;
INSERT INTO @Values (col)
VALUES (@ItemValue);
SET @pos = @index + 1;
END;
WITH cte_XAxis
AS (
SELECT id
,col
FROM @Values
WHERE id % 2 = 1
)
,cte_YAxis
AS (
SELECT id
,col
FROM @Values
WHERE id % 2 = 0
)
--INSERT INTO @ReturnValue
,cte_Coordinates
AS (
SELECT xa.col + ISNULL(',' + ya.col, '') AS Coordinates
FROM cte_XAxis xa
LEFT JOIN cte_YAxis ya ON xa.ID = (ya.ID - 1)
)
INSERT INTO @ReturnValue
SELECT STUFF((
SELECT ';' + Coordinates
FROM cte_Coordinates t2
FOR XML PATH('')
), 1, 1, '')
RETURN;
END
GO
用法
SELECT *
FROM [udf_CoordinatesGrouper]('TextA,TextB,TextC,TextD,TextE,TextF', ',')
GO