Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 Разбить строку на записи через CTE  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72914
declare @d varchar(max)='11111,22,333,'

;with v(i, period) as (
	select CHARINDEX(',',@d), SUBSTRING(@d, 0, CHARINDEX(',',@d)) 
	union all
	select CHARINDEX(',', @d, i+1),SUBSTRING(@d, i+1, CHARINDEX(',',@d)-1) 
	from v 
	where i>0
)
select * from v where i>0
Если через запятую перечислены строки одинаковой длины, то все в порядке, а если разной, то получается ерунда.
Не могу понять, где я налажал.
30 сен 15, 16:37    [18215882]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1451
Antonariy,

а чем не устраивает по старинке через xml?

declare @d varchar(max), @x xml
set @d='11111,22,333,'

set @x = convert(xml, '<a>' + replace(@d, ',', '</a><a>') + '</a>')
select T.c.value('.', 'varchar(255)') from @x.nodes('/a') T(c) where T.c.exist('text()') = 1
30 сен 15, 17:03    [18216125]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72914
Тем, что это не единственная строка, а набор записей.

id строка
1 11111;22;333;
2 345;567;5643;
30 сен 15, 17:18    [18216271]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72914
Соответственно на выходе должно быть
idperiod
1 1111
122
1333
2345
2567
25643
30 сен 15, 17:20    [18216287]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
iap
Member

Откуда: Москва
Сообщений: 47000
Antonariy,

лучше использовать не CTE, а таблицу целых чисел.
Например: Функция, которая делит строку на слова
В той теме и ещё варианты есть.
30 сен 15, 17:23    [18216317]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1451
Antonariy
Соответственно на выходе должно быть
idperiod
1 1111
122
1333
2345
2567
25643


create function xml_tbl (@id int, @value varchar(max), @sep varchar(255))
returns table 
as 
return (
select @id as id, T.c.value('.', 'varchar(255)') as value
from (select convert(xml, '<a>' + replace(@value, @sep, '</a><a>') + '</a>') as val) X
    outer apply X.val.nodes('/a') T(c)
where T.c.exist('text()')=1


)

declare @tbl table (id int, value varchar(max))
insert into @tbl values (1, '11111;22;333;')
insert into @tbl values (2, '345;567;5643;')


select t.id,
       X.value
from @tbl t
    outer apply dbo.xml_tbl(t.id, t.value, ';') X
30 сен 15, 17:30    [18216374]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72914
iap,

Чем лучше, шустрее?
И что-то не догоняю, как прикрутить ParseString к select id, str2parse from tbl1
30 сен 15, 17:31    [18216380]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
samoxod
Member

Откуда: Москва
Сообщений: 31
Antonariy,
declare @d varchar(max)='11111,22,333,'

;with v(i, period) as (
	select CHARINDEX(',',@d), SUBSTRING(@d, 0, CHARINDEX(',',@d)) 
	union all
	select CHARINDEX(',', @d, v.i+1), SUBSTRING(@d, v.i+1, ABS(CHARINDEX(',', @d, v.i+1)-v.i)-1 )
	from v 
	where i>0
)
select * from v where i>0
30 сен 15, 17:34    [18216395]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72914
felix_ff,

Спасибо, но мучают меня сомнения насчет производительности.
30 сен 15, 17:35    [18216410]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
felix_ff
Member

Откуда: Moscow
Сообщений: 1451
Antonariy
felix_ff,

Спасибо, но мучают меня сомнения насчет производительности.


где то на форуме, была тема про парсинг строки поищите, там даже invm или churupaha по-моему замеры производил различных методов, xml довольно шустро бегает.

ну если хотите можете поизвращаться с stuff/substring но геммора много.

в любом случае вам для получения необходимого результата будет необходим некий метод дающий результирующую таблицу которую потом вы кроме как apply не примапите
30 сен 15, 17:38    [18216425]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
СТУДЕНТ123
Guest
Через табличную функцию, у меня в таком виде хранятся права доступа к вкладкам самописной системы, знаю криво, но переписывать в нормальные вид приложение не особо хочется ((

ALTER FUNCTION [dbo].[GETxRULESxUSERS] 
( @LIST	NVARCHAR(4000), @DELIMETER	NCHAR(1) = N','
) RETURNS TABLE AS RETURN	
WITH [LIST] ([NO],[POS],[TO]) AS (
	SELECT	0,0,0
UNION ALL
	SELECT	L.[NO] + 1,L.[TO] + 1,I.[TO]
	FROM	[LIST] L CROSS APPLY (SELECT CHARINDEX(@DELIMETER,@LIST + @DELIMETER,L.[TO] + 1)) I ([TO])
	WHERE	I.[TO] > 0
)	SELECT	[NO],SUBSTRING(@LIST,[POS],[TO]-[POS])	AS ITEM	,[POS]
	FROM	[LIST]
	WHERE	[TO] > [POS]


Теперь результат:

DECLARE @TABLE TABLE (ID INT, STRS VARCHAR(MAX))

INSERT INTO @TABLE SELECT 1,'11111;22;333;'
INSERT INTO @TABLE SELECT 2,'345;567;5643;'

SELECT * FROM @TABLE

SELECT T.ID, GRU.ITEM
FROM @TABLE AS T CROSS APPLY dbo.GETxRULESxUSERS(T.STRS,';') AS GRU
30 сен 15, 17:41    [18216442]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
invm
Member

Откуда: Москва
Сообщений: 9405
Antonariy
Спасибо, но мучают меня сомнения насчет производительности.
15097121
30 сен 15, 17:41    [18216446]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
СТУДЕНТ123
Guest
ALTER на CREATE сами замените, что то я упустил этот момент
30 сен 15, 17:42    [18216459]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
Antonariy
Member

Откуда: ☭
Сообщений: 72914
invm
Antonariy
Спасибо, но мучают меня сомнения насчет производительности.
15097121
Внезапно выходит, что вариант с xml самый шустрый, а мой практически самый тормозной :)

Спасибо за науку.
30 сен 15, 17:52    [18216527]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на записи через CTE  [new]
Valer
Member

Откуда:
Сообщений: 277
Antonariy, вариант с CTE
;
declare @delim  char(1)
select @delim = ';'
declare @tbl table (id int, value varchar(max))
insert into @tbl values (1, '11111;22;333;')
insert into @tbl values (2, '345;567;5643;')
;
with tdelim   as 
( select 
    t.id
   ,v.number 
from master.dbo.spt_values v 
 , @tbl t
where  substring( t.value , v.number ,1) = @delim
and v.type='P' 
and v.number <= len(t.value) and v.number > 0 
--- + учитываем начало 
union select id, 0 from  @tbl  
),
  tdelim1   as 
( select 
    d.id
   ,d.number  as start
   ,min( d1.number  ) as finish
from tdelim  d
inner join tdelim  d1
  on d1.id =d.id
  and d.number < d1.number
group by     d.id  ,d.number   
 )
select d.id
 ,d.start 
 , d.finish 
 ,substring( t.value , d.start+1  ,  d.finish -  d.start -1  ) as word
from tdelim1 d
  inner join @tbl t
    on t.id =d.id
order by d.id
1 окт 15, 14:06    [18220645]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить