替换SQL SELECT查询中出现的偶数/奇数字符串

替换SQL SELECT查询中出现的偶数/奇数字符串,sql,sql-server,sql-server-2012,Sql,Sql Server,Sql Server 2012,假设我在SQLServer2012上运行此查询 SELECT Coordinates FROM Table 我得到了这个结果: TextA,TextB,TextC,TextD,TextE,TextF select * from dbo.Split('123,456,789,000', ',') Nr Typ Value 1 X 123 1 Y 456 2 X 789 2 Y 000 我想解析这个结果并得到以下结果: TextA,TextB;T

假设我在SQLServer2012上运行此查询

SELECT Coordinates 
FROM Table
我得到了这个结果:

TextA,TextB,TextC,TextD,TextE,TextF
select * from dbo.Split('123,456,789,000', ',')

Nr  Typ  Value
1   X    123
1   Y    456
2   X    789
2   Y    000
我想解析这个结果并得到以下结果:

TextA,TextB;TextC,TextD;TextE,TextF
也就是说,每对后面都有一个分号


有可能做到这一点吗

这将实现您想要的功能:

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;

编辑1:我刚刚注意到结果的最后一行有一个问题,也是一个X,现在正试图解决这个问题

编辑2:修复了编辑1中的错误

此查询将获得一个函数,该函数将按如下结果拆分输入字符串:

TextA,TextB,TextC,TextD,TextE,TextF
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

使用递归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。

创建此函数以对坐标进行分组。该功能已根据您的需求进行了调整,其功能也根据您的需求进行了扩展

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
用法


什么是连接你的X,Y对?是否有某种id指示X和Y应该配对?感谢Jean的及时回复。X和Y只是文本。我想格式化结果,以便每找到两个逗号,就用分号替换一个。什么sql server?TSQL?博士后?没有简单的方法可以分开你的弦。你需要一个函数什么的。你对函数本身满意吗?在SQL端这样做有什么原因吗。使用C或另一种客户端编程语言,这类任务要容易得多。问题不在于数据行,而在于一个字段,其中包含,s,他希望每2行替换一个字段。如果您使用StackOverflow中可用的标准SplitString函数之一将逗号分隔的字符串解析为多行,然后,同样的算法可以产生所需的结果,只需将FROM TestTable替换为FROM dbo.SplitStringcolumn值。。。这会有点尴尬,但它会起作用。一切都是相对的,但我不知道有什么更快的方法。您可以对此查询进行一些微优化,其中一些会影响可读性。另一种方法是使用标量函数,这肯定会慢一些。使用XML可能是可能的,也可能更快。正如您上面所建议的那样,在客户端进行操作肯定会更快。SQL Server在字符串操作方面很差劲。读得不错,结论:长字符串上没有CTE方法:正如我所说的SQL Server在字符串操作方面差劲,所以毫不奇怪。是的,如果你需要做一些时髦的字符串工作,你真的想要一个CLR@Hogan谢谢你的这种方法。在我的例子中,行数不高,所以性能不是问题。如果除了列坐标,我还想显示其他列呢?我应该把这个放在哪里?已尝试将此添加到WITH范围外的最后一个选择,但每行显示相同的信息。我应该用另一张临时桌子吗?@Gonzalo-MWillemse写道,请感谢他。要在多个列上使用,您应该创建一个函数,然后调用它。也许MWillemse会修改答案,将其包括在内?