#sql #sql-server #tsql #user-defined-functions
Вопрос:
Я пытаюсь разделить предложение с неограниченным количеством символов на 7 кратных, используя SQL UDF. Это означает, что я пытаюсь разбить предложение на строки по 7 символов в каждой строке. Это подход, который, по моему мнению, был самым быстрым.
CREATE OR ALTER FUNCTION dbo.UDF_SplitStringIntoRows
(
@inputstring nvarchar(MAX)
)
RETURNS @OutputTbl TABLE
(
txt nvarchar(MAX),
seq INT IDENTITY
)
AS
BEGIN
IF(LEN(@inputstring) <= 40)
BEGIN
INSERT INTO @OutputTbl (txt)
SELECT SUBSTRING(@inputstring, 1,7) UNION
SELECT SUBSTRING(@inputstring, 8,7) UNION
SELECT SUBSTRING(@inputstring, 15,7) UNION
SELECT SUBSTRING(@inputstring, 23,7) UNION
SELECT SUBSTRING(@inputstring, 30,7) UNION
SELECT SUBSTRING(@inputstring, 37,7) UNION
SELECT SUBSTRING(@inputstring, 44,7)
END
RETURN
END
Мой вопрос:
SELECT *
FROM dbo.UDF_SplitStringIntoRows('This is a demo function which') AS USSIR
WHERE USSIR.txt <> ''
Выход:
Что нарушает последовательность предложения. Я что-то здесь упускаю? Пожалуйста, предложите.
Комментарии:
1. Ваша функция, похоже, разбивается на 7 символов в строке, что не то, о чем вы просите, возможно, помогут примеры данных и желаемые результаты.
2. Существуют гораздо лучшие способы разделения строк без необходимости многократного выбора и объединения, рассмотрите возможность использования
cross apply
с таблицей подсчета3. У вас также есть единичная ошибка в вычислениях подстрок
4.
LEN(@inputstring) <= 40
Согласуется сSUBSTRING(@inputstring, 44,7)
?5. Если вы ожидаете только строку из 40 (44?) символов, зачем использовать
nvarchar(max)
? А что произойдет, если вы передадите строку длиной более 40 символов (функция с удовольствием возьмет мегабайты)?
Ответ №1:
Только что выяснил ошибку. На самом деле все портит Профсоюз. Я просто заменил Union на Union All, и, похоже, он получает желаемый результат.
Еще раз спасибо.
Ответ №2:
Вам гораздо лучше использовать встроенную табличную функцию
CREATE OR ALTER FUNCTION dbo.UDF_SplitStringIntoRows
(
@inputstring nvarchar(56),
@splitSize int
)
AS RETURN
SELECT
SUBSTRING(@inputstring, n * @splitSize 1, @splitSize) txt,
ROW_NUMBER() OVER (ORDER BY n) seq
FROM (VALUES
(0),(1),(2),(3),(4),(5),(6),(7)
) v(n)
WHERE n * @splitSize 1 >= LEN(@inputstring);
GO
Если строка может быть неограниченной длины, вы можете использовать функцию подсчета Ицика Бен-Гана для создания строк
CREATE OR ALTER FUNCTION dbo.GetNums
(@low AS BIGINT = 1, @high AS BIGINT)
RETURNS TABLE
AS
RETURN
WITH
L0 AS ( SELECT 1 AS c
FROM (VALUES(1),(1),(1),(1),(1),(1),(1),(1),
(1),(1),(1),(1),(1),(1),(1),(1)) AS D(c) ),
L1 AS ( SELECT 1 AS c FROM L0 AS A CROSS JOIN L0 AS B ),
L2 AS ( SELECT 1 AS c FROM L1 AS A CROSS JOIN L1 AS B ),
L3 AS ( SELECT 1 AS c FROM L2 AS A CROSS JOIN L2 AS B ),
Nums AS ( SELECT ROW_NUMBER() OVER(ORDER BY (SELECT NULL)) AS rownum
FROM L3 )
SELECT TOP(@high - @low 1)
rownum AS rn,
@high 1 - rownum AS op,
@low - 1 rownum AS n
FROM Nums
ORDER BY rownum;
GO
CREATE OR ALTER FUNCTION dbo.UDF_SplitStringIntoRows
(
@inputstring nvarchar(MAX),
@splitSize int
)
AS RETURN
SELECT
SUBSTRING(@inputstring, n * @splitSize 1, @splitSize) txt,
rownum AS seq
FROM dbo.GetNums(0, (LEN(@inputstring) - 1) / @splitSize) v;