TSQL - 解析地址函数,无法得到 return 结果

TSQL - Parse address function, unable to return result

函数 px_explode 将提供两个参数:

最终结果将如下所示:

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

并将return

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

How can I avoid the infinite loop I ran into and what am I missing?


代码:

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

我最喜欢的是 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>

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

循环不好,多语句 table 值函数也是如此(例如,您定义 table 的地方)。如果性能很重要,那么您需要计数 table 和内联 table 值函数 (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

哪个returns

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

针对 table 它看起来像这样:

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