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
函数 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