如何在字母和数字字符块之间插入连字符

时间:2017-05-09 06:31:56

标签: sql sql-server sql-server-2012

我需要在字符串中的alpha和数字文本块之间插入连字符。 我甚至不确定如何解决这个问题。

ABC123 -> ABC-123
ABC123XYZ -> ABC-123-XYZ
D123 -> D-123
123C -> 123-C

2 个答案:

答案 0 :(得分:4)

这个可以为您提供单一价值。

DECLARE @CODE VARCHAR(50) = '12ABC123XYZ'
    ,@NEWCODE VARCHAR(100) = ''

;WITH CTE
AS (
    SELECT NUMBER
        ,SUBSTRING(@CODE, NUMBER, 1) AS VAL
    FROM master.dbo.spt_values
    WHERE TYPE = 'P'
        AND number BETWEEN 1
            AND LEN(@CODE)
    )
SELECT @NEWCODE = @NEWCODE + CASE 
        WHEN ISNUMERIC(C1.VAL) <> ISNUMERIC(ISNULL(C2.VAL, C1.VAL))
            THEN '-' + C1.VAL
        ELSE C1.VAL
        END
FROM CTE C1
LEFT JOIN CTE C2 ON C1.number = C2.number + 1

SELECT @NEWCODE

结果: 12-ABC-123-XYZ

如果您希望这与表列一起使用,则需要创建标量函数。

CREATE FUNCTION CODE_SPLIT  
(

    @CODE VARCHAR(50)
)
RETURNS VARCHAR(100)
AS
BEGIN

     DECLARE @NEWCODE VARCHAR(100) ='';

    ;WITH CTE
    AS (
        SELECT NUMBER
            ,SUBSTRING(@CODE, NUMBER, 1) AS VAL
        FROM master.dbo.spt_values
        WHERE TYPE = 'P'
            AND number BETWEEN 1
                AND LEN(@CODE)
        )
    SELECT @NEWCODE = @NEWCODE + CASE 
            WHEN ISNUMERIC(C1.VAL) <> ISNUMERIC(ISNULL(C2.VAL, C1.VAL))
                THEN '-' + C1.VAL
            ELSE C1.VAL
            END
    FROM CTE C1
    LEFT JOIN CTE C2 ON C1.number = C2.number + 1

    RETURN @NEWCODE

END
GO

并在实际的桌子上调用它

<强>架构:

SELECT *  INTO #TAB FROM(
SELECT 'ABC123' AS CODE
UNION ALL
SELECT 'ABC123XYZ'
UNION ALL
SELECT 'D123'
UNION ALL
SELECT '123C'
)A

SELECT CODE, dbo.CODE_SPLIT(CODE) AS NEWCODE FROM #TAB

<强>结果:

+-----------+-------------+
|   CODE    |   NEWCODE   |
+-----------+-------------+
| ABC123    | ABC-123     |
| ABC123XYZ | ABC-123-XYZ |
| D123      | D-123       |
| 123C      | 123-C       |
+-----------+-------------+

答案 1 :(得分:1)

patindex('%[0-9]%')返回第一个数字的索引。
patindex('%[^0-9]%')返回第一个非数字字符的索引。
您可以像这样使用recursive CTEPATINDEX

DECLARE @SampleData AS TABLE
(
   TextValue varchar(100)
)
INSERT INTO @SampleData
VALUES ('ABC124'), ('ABC123XYZ'), ('123C'), ('ABC'), ('1A2B3C')

;WITH cte AS
(
   SELECT    sd.TextValue AS RootText,
         sd.TextValue AS CurrentText, 
         CAST('' AS varchar(100)) AS Result
   FROM @SampleData sd

   UNION ALL

      SELECT    
            c.RootText,
            CASE       
                   WHEN patindex('%[0-9]%', c.CurrentText) = 0 OR patindex('%[^0-9]%', c.CurrentText) = 0
                      THEN ''
                   WHEN patindex('%[0-9]%', c.CurrentText) > patindex('%[^0-9]%', c.CurrentText) 
                      THEN RIGHT(c.CurrentText, len(c.CurrentText) - patindex('%[0-9]%', c.CurrentText) + 1)
                   ELSE RIGHT(c.CurrentText, len(c.CurrentText) - patindex('%[^0-9]%', c.CurrentText) + 1)
            END AS CurrentText, 
            CAST(
                  CASE 
                      WHEN patindex('%[0-9]%', c.CurrentText) = 0 OR patindex('%[^0-9]%', c.CurrentText) = 0
                            THEN Result + '-' + c.CurrentText
                      WHEN patindex('%[0-9]%', c.CurrentText) > patindex('%[^0-9]%', c.CurrentText) 
                            THEN Result + '-' + LEFT(CurrentText, patindex('%[0-9]%', c.CurrentText) - 1)
                      ELSE Result + '-' + LEFT(CurrentText, patindex('%[^0-9]%', c.CurrentText) - 1)
                  END AS varchar(100)
                ) AS Result
   FROM cte c
   WHERE LEN(CurrentText) > 0
)
SELECT cte.RootText, STUFF(cte.Result, 1,1,'') AS Result FROM cte
WHERE cte.CurrentText = ''

演示链接:http://rextester.com/FTYA72053