函数px_explode将提供两个参数:
最终结果如下:
SELECT * FROM dbo.px_explode('xxy', 'alfaxxybetaxxygama')
并将返回
但是... 查询不会完成执行,所以我假设我在这里遇到了一个无限循环,现在假设这个,我的问题可能是。
我怎样才能避免遇到无限循环以及缺少什么?
代码:
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
答案 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()