在我的问题中,SQL Server,T-SQL是否有更快的方法来对以下字符串进行子串?

时间:2010-01-15 08:16:26

标签: sql-server algorithm tsql substring performance

我有像

这样的字符串

OPEN SYSTEMS SUB GR(GM / BTIB(1111)/ BTITDBL(2222)/ BTVY(4444)/ ACSVTYSAG)

在我的GROUPS专栏下的数据库中。

我想要做的是从该字符串中提取2222。我正在使用的代码就是这样。

    SELECT 
        SUBSTRING(GROUPS, CHARINDEX('(',GROUPS, CHARINDEX('(',GROUPS, CHARINDEX('(',GROUPS,0)+1)+1)+1, 4 ) AS GroupNo

    FROM MY_TABLE

    WHERE

    ISNUMERIC(SUBSTRING(GROUPS, CHARINDEX('(',GROUPS, CHARINDEX('(',GROUPS, CHARINDEX('(',GROUPS,0)+1)+1)+1, 4 )) = 1

我需要通过更改我正在使用的子字符串方式或更改某些逻辑来固定上面的代码。你能告诉我在我的代码中可以改进哪些内容吗?

3 个答案:

答案 0 :(得分:1)

如果您经常这样做,我会考虑通过触发器将insert / update / delete上的数据解析为单独的表(比如MY_TABLE_ELEMENTS),然后从MY_TABLE中选择SELECT加入{{ 1}}。

例如,您可以使用split函数(拆分“(”,如果我正确理解您的代码),将每个完整的拆分元素存储到MY_TABLE_ELEMENTS中,或者只解析数字部分。

答案 1 :(得分:1)

您可以实现一个实现regex的CLR UDF。

答案 2 :(得分:1)

基于集合的实现。

这比单行代码的性能要差,但对于更大的结果集应该更好地扩展,特别是如果使用静态数字表替换生成动态数字表的CTE。

DECLARE @t TABLE
(groups VARCHAR(250))

INSERT @t
VALUES ('OPEN SYSTEMS SUB GR (GM/BTIB(1111)/BTITDBL(2222)/BTVY(4444)/ACSVTYSAG)')

INSERT @t
VALUES ('OPEN SYSTEMS SUB GR (GM/BTIB(1111)/BTITDBL(3333)/BTVY(4444)/ACSVTYSAG)')

DECLARE @chr_delim CHAR(1)
SET @chr_delim = '('

-- nums_cte generates a dynamic numbers table
-- replace this with your own numbers table if you have one
;WITH nums_cte 
AS 
( 
        SELECT 1 AS n 
        UNION ALL 
        SELECT n+1 FROM nums_cte 
        WHERE n < 250
) 
,splitCTE    
AS
(
        SELECT  SUBSTRING(s,n,CHARINDEX(@chr_delim, s + @chr_delim,n) -n) AS ELEMENT
                ,s
                ,ROW_NUMBER() OVER (PARTITION BY s
                                    ORDER BY n
                                   ) AS rn
        FROM (SELECT groups AS s FROM @t) AS D
        JOIN nums_cte
        ON n <= LEN(s)
        AND SUBSTRING(@chr_delim + s,n,1) = @chr_delim 
)
SELECT LEFT(ELEMENT,4) AS GroupNo
       ,s AS originalString
FROM splitCTE
WHERE rn = 4
AND   ISNUMERIC(LEFT(ELEMENT,4)) = 1
OPTION (MAXRECURSION 0)