Как разобрать строку с разделителями в столбцы, используя только строковые функции (SQL Server 2008 R2)? - PullRequest
0 голосов
/ 18 мая 2018

Я хочу разобрать строку с разделителями из поля базы данных в несколько столбцов.Строка может содержать от 0 до 7 компонентов, разделенных специальным символом (char (7) в моем конкретном случае).Там будет не более семи компонентов;если они есть, они будут проигнорированы и включены в разделители в последнем компоненте. Мне нужно сделать это без использования UDF или T-SQL. Я не думаю, что функция синтаксического анализа XML хорошо подходит для этого, но я бы рассмотрела эффективное решение.

Это оставляет функции манипуляции со строками. Поскольку я нахожусь в SQL Server 2008 R2, функция string_split () не является опцией. Кажется, что работает метод грубой силы (ниже), но он громоздкий и нечитаемый.Я был бы заинтересован в любом улучшении этого.

create table #x (a int, delimited_value varchar(8000))
insert into #x values 
 (1, 'abc')
,(2, 'defgh' + char(7) + 'ij' + char(7) + 'klmnop')
,(3, '')
,(4, 'qr' + char(7) + 's' + char(7) + 't' + char(7) + 'u' + char(7) + 'v' + char(7) + 'w' + char(7) + 'xyz')
,(5, '012' + char(7) + char(7) + '3' + char(7))
,(6, char(7) + char(7) + '4567' + char(7) + char(7) + '89')

select a
,substring(delimited_value, 1, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) - 1) as component1
,substring(delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0) + 1, 8000), isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8001) - isnull(nullif(charindex(char(7), delimited_value), 0), 8000) - 1) as component2
,substring(delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0) + 1, 8000), isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8001) - isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) - 1) as component3
,substring(delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0) + 1, 8000), isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8001) - isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) - 1) as component4
,substring(delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0) + 1, 8000), isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8001) + 1 ), 0), 8001) - isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) - 1) as component5
,substring(delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0) + 1, 8000), isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8001) - isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) - 1) as component6
,substring(delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value, isnull(nullif(charindex(char(7), delimited_value), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0), 8000) + 1 ), 0) + 1, 8000), 8000) as component7
from #x

Ответы [ 2 ]

0 голосов
/ 18 мая 2018

Я думаю, что XML-подход был бы здесь простым и эффективным решением.

Пример

Select A.a
      ,B.*
 From  #x A
 Cross Apply (
                Select Pos1 = ltrim(rtrim(xDim.value('/x[1]','varchar(max)')))
                      ,Pos2 = ltrim(rtrim(xDim.value('/x[2]','varchar(max)')))
                      ,Pos3 = ltrim(rtrim(xDim.value('/x[3]','varchar(max)')))
                      ,Pos4 = ltrim(rtrim(xDim.value('/x[4]','varchar(max)')))
                      ,Pos5 = ltrim(rtrim(xDim.value('/x[5]','varchar(max)')))
                      ,Pos6 = ltrim(rtrim(xDim.value('/x[6]','varchar(max)')))
                      ,Pos7 = ltrim(rtrim(xDim.value('/x[7]','varchar(max)')))
                From  (Select Cast('<x>' + replace(delimited_value,char(7),'</x><x>')+'</x>' as xml) as xDim) as A 
             ) B

Возвращает

a   Pos1    Pos2    Pos3    Pos4    Pos5    Pos6    Pos7
1   abc     NULL    NULL    NULL    NULL    NULL    NULL
2   defgh   ij      klmnop  NULL    NULL    NULL    NULL
3           NULL    NULL    NULL    NULL    NULL    NULL
4   qr      s       t       u       v       w       xyz
5   012             3               NULL    NULL    NULL
6                   4567            89      NULL    NULL
0 голосов
/ 18 мая 2018

Несмотря на требование не использовать функцию, я публикую решение, которое ее использует.Это встроенная табличная функция и она безумно быстра.Если не использовать CLR, вы не найдете там быстрого сплиттера.Вы можете найти статью и код здесь.http://www.sqlservercentral.com/articles/Tally+Table/72993/

Если вам не нравится этот, есть несколько других отличных вариантов здесь.https://sqlperformance.com/2012/07/t-sql-queries/split-strings

Используя сплиттер Jeff Moden (из первой ссылки выше), ваш код будет таким простым.

select x.a
    , component1 = max(case when y.ItemNumber = 1 then y.Item end)
    , component2 = max(case when y.ItemNumber = 2 then y.Item end)
    , component3 = max(case when y.ItemNumber = 3 then y.Item end)
    , component4 = max(case when y.ItemNumber = 4 then y.Item end)
    , component5 = max(case when y.ItemNumber = 5 then y.Item end)
    , component6 = max(case when y.ItemNumber = 6 then y.Item end)
    , component7 = max(case when y.ItemNumber = 7 then y.Item end)
from #x x
cross apply dbo.DelimitedSplit8K(x.delimited_value, char(7)) y
group by x.a
...