Публикация

Парсинг строки для использования в качестве набора строк в MSSQL

в продолжение темы http://www.community.terrasoft.ru/blogs/10000
версия 2 :smile:

Чтобы в MSSQL из строки получить набор строк (например, для использования в качестве параметра для select ... where ... in (***)), предлагаю следующее:

declare @input_str nvarchar(4000) = '' -- входная строка
declare @IncludedTablesStringTable TABLE (Code uniqueidentifier) -- смени тип
declare @IncludedTablesStringCode nvarchar(4000)
declare @delimeter nvarchar(4000) = ', '
declare @pos int = 0
declare @len int = LEN(@input_str + cast(2 AS varchar)) - 1
declare @lend int = LEN(@delimeter + cast(2 AS varchar)) - 1
declare @oldpos int = 0
declare @substr nvarchar(4000)

while (@pos = @len)
begin
        SET @substr = SUBSTRING(@input_str, @pos, @lend)
        IF (@substr = @delimeter OR @pos = @len)
        begin
                SET @substr = SUBSTRING(@input_str, @oldpos,
                        @pos - @oldpos + case when (@pos = @len) then 1 else 0 end
                )
                INSERT INTO @IncludedTablesStringTable (Code) VALUES (@substr)
                SET @pos = @pos + @lend
                SET @oldpos = @pos
                continue
        end
        SET @pos = @pos + 1
end

(SELECT Code FROM @IncludedTablesStringTable)

Комментарии:
- для использования вставляете (select Code from @IncludedTablesStringTable) туда, где нужен набор строк

- почему все строки nvarchar(4000)? Меня учили, что программа должна работать как можно в большей вариантивности входящих значений. А так как ничто не мешает использовать какую-то странную кодировку или какой-то гигантский разделитель, из ограничений на переменные поставил только юникод.

- что это?

declare @len int = LEN(@input_str + cast(2 AS varchar)) - 1
declare @lend int = LEN(@delimeter + cast(2 AS varchar)) - 1
дело в том, что нам нужен размер разделителя и строки, но LEN() обрезает пробелы в конце (из-за этого я потратил на часок больше времени :cry:). Поэтому идем на хитрость: добавляем знак в конце, считаем, отнимаем единицу. Ну а CAST() используется т.к. если вставлять код со строками в exec(), то начинаются сложности всякие, а так - мы обходим эту проблему. Конечно, можно использовать и другие решения для учета конечных пробелов, но все, что придумал, показались не надежными

- скрипт начинает путаться если разделители идут подряд (не разделены смыслом :lol:), т.е. при разделителе ',' строка '12345,6789,321,,,' распарсится в

12345
6789
321

,

- и последнее, в declare @IncludedTablesStringTable не забудьте указать тип данных тот, который вам нужен

Нравится

Поделиться

1 комментарий

вот тут разбираются нормальные способы :lol:
https://sqlperformance.com/2012/07/t-sql-queries/split-strings

Показать все комментарии