在特定字符串组之前填充或插入字符串

时间:2014-06-26 01:48:24

标签: sql-server tsql

我在历史表中有一个包含这样数据的表。

MEMBER_ID   COLORS
1           1) Red 2) Blue 3) Green

我需要修改或选择数据,以便结果集看起来像这样。

MEMBER_ID   COLORS
1           #1) Red #2) Blue #3) Green

简而言之,在数字和右括号之前插入英镑。

我尝试使用CHARINDEX,但我尝试过的功能无效。

6 个答案:

答案 0 :(得分:2)

我不确定您的数据有多可预测,因此我会提供一个建议,您可以使用类似的PATINDEX s扩展它以适用于任何其他极端情况。

我在此建议中的假设是每个文本可能以任何单个数字开头(例如" 1)" )没有前面的空格,你只有一个或两个数字的索引(只是扩展我对更高指数的建议),并且唯一要转换的数字是那些后面跟着的数字。

-- first update, done only once
-- starts with 1)  ...any single digit, no preceeding space, followed by parens
;WITH TMP AS (SELECT Id FROM #SRC WHERE PATINDEX('[0-9][)]%', Colors) = 1)
    UPDATE MyTable SET Colors = STUFF(Colors, 1, 0, '#')
     WHERE Id IN (SELECT Id FROM TMP);

-- (you could repeat the above for strings starting with a double digit, if necessary)

-- next two updates are looped until pattern is no longer found
DECLARE @affected int = 1;
WHILE @affected > 0
  BEGIN
    -- e.g. 1)  ...any single digit not yet converted and followed by parens
    ;WITH TMP AS (SELECT Id FROM #SRC WHERE PATINDEX('%[^#0-9][0-9][)]%', Colors) > 1)
        UPDATE MyTable SET Colors = STUFF(Colors, PATINDEX('%[^#0-9][0-9][)]%', Colors)+1, 0, '#')
         WHERE Id IN (SELECT Id FROM TMP);    
     SET @affected = @@rowcount;
  END

SET @affected = 1;    
WHILE @affected > 0
  BEGIN
    -- e.g. 10)  ...any two digits not yet converted and followed by parens
    ;WITH TMP AS (SELECT Id FROM #SRC WHERE PATINDEX('%[^#0-9][0-9][0-9][)]%', Colors) > 1)
        UPDATE MyTable SET Colors = STUFF(Colors, PATINDEX('%[^#0-9][0-9][0-9][)]%', Colors)+1, 0, '#')
         WHERE Id IN (SELECT Id FROM TMP);    
     SET @affected = @@rowcount;
  END

所以,如果你从这三行开始:

Id  Colors
1   1) Red 2) Blue 3) Green
2   1) Red 20) Blue 30) Green
3   1) Red 20) Blue 3) Green
4   9) Red 10) Blue No.4 11) Green

上述例程将产生:

Id  Colors
1   #1) Red #2) Blue #3) Green
2   #1) Red #20) Blue #30) Green
3   #1) Red #20) Blue #3) Green
4   #9) Red #10) Blue No.4 #11) Green

答案 1 :(得分:2)

您可以使用Replace (Colors, ' 1', ' #1')命令将数字1转换为#1。并且必须对每个数字使用Replace命令。换句话说,您的查询必须写成以下内容:

SELECT Member_Id, LTRIM(REPLACE(
                        REPLACE(
                            REPLACE(
                                REPLACE(
                                    REPLACE(
                                        REPLACE(
                                            REPLACE(
                                                REPLACE(
                                                    REPLACE(' '+Colors,' 1',' #1')
                                                    ,' 2',' #2')
                                                ,' 3', ' #3')
                                            ,' 4',' #4')
                                        ,' 5',' #5')
                                    ,' 6',' #6')
                                ,' 7',' #7')
                            ,' 8',' #8')
                        ,' 9',' #9')) AS Colors
From YourTable

另一种方法:

CREATE FUNCTION dbo.f(@T NVARCHAR(100))
RETURNS NVARCHAR(100)
AS BEGIN
    DECLARE @R NVARCHAR(100)='',
            @IsDigit BIT = 0,
            @Index INT = 1
    WHILE @Index<=LEN(@T)BEGIN
        IF (SUBSTRING(@T,@Index,1) IN ('1','2','3','4','5','6','7','8','9') AND @IsDigit = 0) BEGIN
            SET @R = @R + '#'+SUBSTRING(@T,@Index,1)
            SET @IsDigit = 1
        END ELSE BEGIN
            SET @R = @R + SUBSTRING(@T,@Index,1)
            SET @IsDigit = 0
        END
        SET @Index = @Index + 1
    END
    RETURN @R
END

Select Member_ID, dbo.f(Colors)
From YourTable

答案 2 :(得分:2)

使用PATINDEX()STUFF()CTE和递归查询(Fiddle Demo)尝试此操作:

--//Sample data
DECLARE @T TABLE (MEMBER_ID INT, COLOR VARCHAR(100))

INSERT @T (MEMBER_ID, COLOR)
VALUES (1, '1) Red 2) Blue 3) Green'), (2, '1) Yellow 2) Black 3) Orange')


--//Replace @T with your table name
;WITH CTE AS
(
    SELECT MEMBER_ID,  STUFF(COLOR, PATINDEX('%[0-9][)][ ]%', COLOR), 0, '#') COLOR, 1 NUMBER
    FROM @T
    UNION ALL
    SELECT CTE.MEMBER_ID, STUFF(CTE.COLOR, PATINDEX('%[^#][0-9][)][ ]%', CTE.COLOR) + 1, 0, '#'), NUMBER + 1 
    FROM CTE JOIN @T T
        ON CTE.MEMBER_ID = T.MEMBER_ID
    WHERE PATINDEX('%[^#][0-9][)][ ]%', CTE.COLOR) > 0
),
CTE2 AS
(
    SELECT *, ROW_NUMBER() OVER (PARTITION BY MEMBER_ID ORDER BY NUMBER DESC) rn
    FROM CTE
)
SELECT MEMBER_ID,COLOR FROM CTE2 WHERE RN = 1

结果:

| MEMBER_ID | COLOR                           |
|-----------|---------------------------------|
|         1 | #1) Red #2) Blue #3) Green      |
|         2 | #1) Yellow #2) Black #3) Orange |

答案 3 :(得分:1)

假设MS SQL Server ......最简单的方法是: 选择MEMBER_ID,REPLACE(REPLACE(替换(颜色,'1','#1'),'2','#2'),'3','#3')AS COLORS

答案 4 :(得分:1)

如果您Numbers stored in sequence [1), 2), 3)...]可以执行以下操作

DECLARE @Color VARCHAR(1000) = '1) Red 2) Blue 3) Green'
DECLARE @Count INT = 1
DECLARE @Total INT = LEN(@Color) - LEN(REPLACE(@Color,') ',')')) -- Get Total Colors
-- Loop
WHILE @Count <= @Total
BEGIN
    -- Adding '#'
    SET @Color = REPLACE(' ' + LTRIM(@Color),' ' + CAST(@Count AS VARCHAR) + ')', ' #' + CAST(@Count AS VARCHAR) + ')')
    SET @Count = @Count + 1
END

你可以在表格中更新它。您可以将其设为UDF。

答案 5 :(得分:1)

这是一个有效的功能:

create function doColors(@input varchar(max))
returns varchar(max)
as
begin
    declare @parenIndex int
    declare @numIndex int = 1
    select @parenIndex = CHARINDEX(')', @input, 0)

    while @parenIndex > 0
    begin
        set @numIndex = 1
        while isnumeric(SUBSTRING(@input, @parenIndex-@numIndex, 1)) = 1
        begin
            set @numindex = @numIndex + 1
        end
        if @numIndex > 1 and SUBSTRING(@input, @parenIndex-(@numIndex), 1) = ' '
        begin
            set @input = stuff(@input, @parenIndex-(@numIndex-1), 0, '#')
        end
        select @parenIndex = CHARINDEX(')', @input, @parenIndex+2)
    end
    return @input
end

它基本上找到括号,然后向后查找数字,直到它找不到为止,然后插入#。它适用于任意数量的颜色,并处理颜色名称中的数字,圆括号和#等边缘情况。

1) Red 12) 33 Orange 144) Pink 147) Purple #12 150) Turquoise (light blue) 1024) Brown
1) Mauve 2) Perrywinkle (13) 3) Black (#12)

变为

#1) Red #12) 33 Orange #144) Pink #147) Purple #12 #150) Turquoise (light blue) #1024) Brown
#1) Mauve #2) Perrywinkle (13) #3) Black (#12)

SQL Fiddle