TSQL - 解析地址函数,无法返回结果

时间:2018-01-29 12:11:57

标签: tsql substring sql-function charindex

函数px_explode将提供两个参数:

  • 分离器
  • 字符串

最终结果如下:

SELECT * FROM dbo.px_explode('xxy', 'alfaxxybetaxxygama')

并将返回

enter image description here

但是... 查询不会完成执行,所以我假设我在这里遇到了一个无限循环,现在假设这个,我的问题可能是。

  

我怎样才能避免遇到无限循环以及缺少什么?

代码:

CREATE FUNCTION dbo.px_explode 

    (@separator VARCHAR(10), @string VARCHAR(2000))

 RETURNS @expl_tbl TABLE 

    (val VARCHAR(100))

AS

BEGIN

IF (CHARINDEX(@separator, @string) = 0) and (LTRIM(RTRIM(@string)) <> '')

    INSERT INTO @expl_tbl VALUES(LTRIM(RTRIM(@string)))

ELSE

BEGIN

    WHILE CHARINDEX(@separator, @string) > 0

    BEGIN

        IF (LTRIM(RTRIM(LEFT(@string, CHARINDEX(@separator, @string) - 1))) 
   <> '')

            INSERT INTO @expl_tbl VALUES(LTRIM(RTRIM(LEFT(@string, 
 CHARINDEX(@separator, @string) - 1))))


     END

    IF LTRIM(RTRIM(@string)) <> ''

        INSERT INTO @expl_tbl VALUES(LTRIM(RTRIM(@string)))

 END

RETURN 

END

2 个答案:

答案 0 :(得分:1)

循环不好,mutli语句表值函数也是如此(例如,您定义表的位置)。如果性能很重要,那么您需要一个计数表和内联表值函数(iTVF)。

要获得解决此问题的高效方法,我首先会抓取Ngrams8k的副本。您正在寻找的解决方案如下所示:

DECLARE @string    varchar(8000) = 'alfaxxybetaxxygama',
        @delimiter varchar(20)  = 'xxy'; -- use 

SELECT
  itemNumber = row_number() over (ORDER BY d.p),
  itemIndex  = isnull(nullif(d.p+l.d, 0),1),
  item       = SUBSTRING
             (
               @string, 
               d.p+l.d, -- delimiter position + delimiter length
               isnull(nullif(charindex(@delimiter, @string, d.p+l.d),0) - (d.p+l.d), 8000)
             )
FROM (values (len(@string), len(@delimiter))) l(s,d) -- 1 is fine for l.d but keeping uniform
CROSS APPLY
(
  SELECT -(l.d) union all
  SELECT ng.position
  FROM dbo.NGrams8K(@string, l.d) as ng
  WHERE token = @delimiter
) as d(p); -- delimiter.position

返回

itemNumber           itemIndex            item
-------------------- -------------------- ---------
1                    1                    alfa
2                    8                    beta
3                    15                   gama

对于表格,它看起来像这样:

DECLARE @table table (string varchar(8000));
INSERT @table VALUES ('abcxxyXYZxxy123'), ('alfaxxybetaxxygama');

DECLARE @delimiter varchar(100) = 'xxy';

SELECT * 
FROM @table t
CROSS APPLY
(
  SELECT
    itemNumber = row_number() over (ORDER BY d.p),
    itemIndex  = isnull(nullif(d.p+l.d, 0),1),
    item       = SUBSTRING
               (
                 t.string, 
                 d.p+l.d, -- delimiter position + delimiter length
                 isnull(nullif(charindex(@delimiter, t.string, d.p+l.d),0) - (d.p+l.d), 8000)
               )
  FROM (values (len(t.string), len(@delimiter))) l(s,d) -- 1 is fine for l.d but keeping uniform
  CROSS APPLY
  (
    SELECT -(l.d) union all
    SELECT ng.position
    FROM dbo.NGrams8K(t.string, l.d) as ng
    WHERE token = @delimiter
  ) as d(p) -- delimiter.position
) split; 

结果:

string                    itemNumber           itemIndex            item
------------------------- -------------------- -------------------- ------------------
abcxxyXYZxxy123           1                    1                    abc
abcxxyXYZxxy123           2                    7                    XYZ
abcxxyXYZxxy123           3                    13                   123
alfaxxybetaxxygama        1                    1                    alfa
alfaxxybetaxxygama        2                    8                    beta
alfaxxybetaxxygama        3                    15                   gama

答案 1 :(得分:0)

我最喜欢的是XML分配器。这不需要任何功能,并且完全可以内联。如果你可以在你的数据库中引入一个函数,那么Gareth评论中的建议链接会给你一些非常好的想法。

这很简单,很直接:

DECLARE @YourString VARCHAR(100)='alfaxxybetaxxygama';
SELECT nd.value('text()[1]','nvarchar(max)')
FROM (SELECT CAST('<x>' + REPLACE((SELECT @YourString AS [*] FOR XML PATH('')),'xxy','</x><x>') + '</x>' AS XML)) AS A(Casted)
CROSS APPLY A.Casted.nodes('/x') AS B(nd);

这将首先将您的字符串转换为像这样的XML

<x>alfa</x>
<x>beta</x>
<x>gama</x>

...只需用XML标记替换分隔符xxy即可。其余的很容易从XML .nodes()

中读取