我需要使用deliminiter(例如,)将字符串拆分成多个段
在任何情况下,我都需要相同数量的块,如果文本太短,该函数应返回空字符串。
我想将此存储为Scalar函数,因为与表值函数相比,最好在需要的地方使用它。
我正在寻找像myFunction这样的函数(inputstring,chunknumber)
例如:Inputstring = abc,def,ghi
预期的样本结果:
myFunction(inputstring,1)->'abc'
myFunction(inputstring,3)->'ghi'
myFunction(inputstring,5)->''
答案 0 :(得分:1)
在SQL Server中,您可以使用以下用户定义函数:
CREATE FUNCTION [dbo].[myFunction]
(
@String VARCHAR(MAX),
@ChunkNumber INT
)
RETURNS VARCHAR (100)
AS
BEGIN
DECLARE @Incrementer AS INT = 1;
DECLARE @SliceValue VARCHAR(MAX);
DECLARE @Delimiter AS CHAR(1) = ',';
DECLARE @ReturnObject AS VARCHAR (100) = '';
DECLARE @SplitedValues TABLE (Id INT IDENTITY NOT NULL, Item VARCHAR (100));
IF LEN(@String) < 1 OR @String IS NULL
RETURN @ReturnObject
WHILE @Incrementer != 0
BEGIN
SET @Incrementer = CHARINDEX(@Delimiter, @String);
IF @Incrementer != 0
SET @SliceValue = LEFT(@String, @Incrementer - 1)
ELSE
SET @SliceValue = @String
IF(LEN(@SliceValue) > 0)
INSERT INTO @SplitedValues(Item) VALUES (@SliceValue)
SET @String = RIGHT(@String, LEN(@String) - @Incrementer)
IF LEN(@String) = 0 BREAK
END
SELECT @ReturnObject = Item FROM @SplitedValues WHERE Id = @ChunkNumber;
RETURN @ReturnObject
END
示例执行:
SELECT [dbo].[myFunction] ('abc, def, ghi', 5) -- returns empty
SELECT [dbo].[myFunction] ('abc, def, ghi', 3) -- returns ghi
SELECT [dbo].[myFunction] ('abc, def, ghi', 1) -- returns abc
答案 1 :(得分:0)
这是返回位置编号的基于集合的拆分器的关键所在。值得庆幸的是,杰夫·摩登(Jeff Moden)拥有这样的分裂者。 http://www.sqlservercentral.com/articles/Tally+Table/72993/
他的分离器的代码是:
CREATE FUNCTION [dbo].[DelimitedSplit8K]
--===== Define I/O parameters
(@pString VARCHAR(8000), @pDelimiter CHAR(1))
--WARNING!!! DO NOT USE MAX DATA-TYPES HERE! IT WILL KILL PERFORMANCE!
RETURNS TABLE WITH SCHEMABINDING AS
RETURN
--===== "Inline" CTE Driven "Tally Table" produces values from 1 up to 10,000...
-- enough to cover VARCHAR(8000)
WITH E1(N) AS (
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL
SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1 UNION ALL SELECT 1
), --10E+1 or 10 rows
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS (--==== This provides the "base" CTE and limits the number of rows right up front
-- for both a performance gain and prevention of accidental "overruns"
SELECT TOP (ISNULL(DATALENGTH(@pString),0)) ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
),
cteStart(N1) AS (--==== This returns N+1 (starting position of each "element" just once for each delimiter)
SELECT 1 UNION ALL
SELECT t.N+1 FROM cteTally t WHERE SUBSTRING(@pString,t.N,1) = @pDelimiter
),
cteLen(N1,L1) AS(--==== Return start and length (for use in substring)
SELECT s.N1,
ISNULL(NULLIF(CHARINDEX(@pDelimiter,@pString,s.N1),0)-s.N1,8000)
FROM cteStart s
)
--===== Do the actual split. The ISNULL/NULLIF combo handles the length for the final element when no delimiter is found.
SELECT ItemNumber = ROW_NUMBER() OVER(ORDER BY l.N1),
Item = SUBSTRING(@pString, l.N1, l.L1)
FROM cteLen l
;
现在针对您的情况,您需要另一个功能。没问题,我们可以利用他的分离器。但是我们还需要一个理货表。希望您有其中之一,但如果没有,这是我所使用的。我将其保留为一种视图,因为它非常有用,而且很快。我也是从杰夫·摩登(Jeff Moden)中学到的。
create View [dbo].[cteTally] as
WITH
E1(N) AS (select 1 from (values (1),(1),(1),(1),(1),(1),(1),(1),(1),(1))dt(n)),
E2(N) AS (SELECT 1 FROM E1 a, E1 b), --10E+2 or 100 rows
E4(N) AS (SELECT 1 FROM E2 a, E2 b), --10E+4 or 10,000 rows max
cteTally(N) AS
(
SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) FROM E4
)
select N from cteTally
GO
现在,我们实际上可以开始创建新功能了。将这两个其他组件都放在适当的位置很简单。
create function GetChunkValue
(
@Inputstring varchar(100)
, @ChunkNumber int
) returns table as
return
select ChunkValue = isnull(s.Item, '')
from cteTally t
left join dbo.DelimitedSplit8K(@Inputstring, ',') s on s.ItemNumber = t.N
where t.N = @ChunkNumber
最后是一些使用它的示例代码。
select *
from GetChunkValue('abc, def, ghi', 2)