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

Откуда: KZ
Сообщений: 36
Всем привет! И <многопивавсем>!

У меня тут запара вышла... Задачка следующая,
Вот такая таблица...

with temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
),


Из нее надо разбить строки в подстроку:

1	aa
1	bb
1	aaa
2	bb
2	cc
3	cc
3	dd
4	cc
4	ee


Мои потуги над велосипедом:

cte1 (step, abc, test) as
(
	select 1 as step, abc, CAST(NULL as varchar(100)) 
	from temp
	UNION ALL
	select step + 1, abc, CAST(CHARINDEX('ab', abc) as varchar(100))
	from cte1
	WHERE step <= LEN(abc)
)

select * from cte1
option (maxrecursion 0)


Т.е. я хочу пробежать по всем строкам и найти переходы CHARINDEX('ab') > 1
Если есть, то в новую строку....

Но что мой воспаленный мозг начинает осознавать что я куда то не туда иду...
На простом чистом sql или cte это как то можно реализовать?

FAQ iap я прочитал в первую очередь, не пинайте ))
31 янв 19, 11:48    [21798580]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
msLex
Member

Откуда:
Сообщений: 8091
Если честно, то такие задачи прямо предназначены для CLR функций, но если совсем хочется на TSQL

create function dbo.splitter (@s varchar(8000))
returns table as
return 
	with spllited as (
		select 
			start_pos = 1 
			,  end_pos = nullif(patindex('%[^' + SUBSTRING(@s, 1, 1) + ']%' , @s ) - 1, 0) 
		union all
		select 
			start_pos = s.end_pos + 1 
			, end_pos = s.end_pos + nullif(patindex ('%[^' + SUBSTRING(RIGHT(@s, len(@s) - s.end_pos), 1, 1) + ']%' , RIGHT(@s, len(@s) - s.end_pos) ), 0) - 1 
		from  spllited s
		where 
			end_pos is not null
	)
	select 
		part = SUBSTRING(@s, start_pos, isnull(end_pos, len(@s)) - start_pos + 1)
		, start_pos
		, end_pos = isnull(end_pos, len(@s))
	from spllited
go



with temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)

select *
from temp
cross apply dbo.splitter (abc)
31 янв 19, 12:21    [21798627]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
invm
Member

Откуда: Москва
Сообщений: 9349
create function dbo.fnSplit
(
 @s varchar(max)
)
returns table
as
return (
 with t(p, c, g) as
 (
  select 1, substring(@s, 1, 1), 1

  union all

  select
   t.p + 1, a.c, case when a.c <> t.c then t.g + 1 else t.g end
  from
   t cross apply
   (select substring(@s, p + 1, 1)) a(c)
  where
   a.c > ''
 )
 select substring(@s, min(p), max(p) - min(p) + 1) as s from t group by g
);
go

with temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)
select
 *
from
 temp a cross apply
 dbo.fnSplit(a.abc) b;
go

drop function dbo.fnSplit;
go
31 янв 19, 12:23    [21798632]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31355
swd1986
На простом чистом sql или cte это как то можно реализовать?
Вот даже без CTE, обрабатывайте напильником:
--  Вместо with number/master..spt_values лучше использовать свою таблицу чисел
with number as (
	select distinct number * 2 + 1 as number from master..spt_values where number between 0 and 10
),
temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)
select *, SUBSTRING(abc, number, 2) as S
from temp
	cross join number
where LEN(SUBSTRING(abc, number, 2)) = 2
order by num
31 янв 19, 12:27    [21798640]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
msLex
Member

Откуда:
Сообщений: 8091
alexeyvg
swd1986
На простом чистом sql или cte это как то можно реализовать?
Вот даже без CTE, обрабатывайте напильником:
--  Вместо with number/master..spt_values лучше использовать свою таблицу чисел
with number as (
	select distinct number * 2 + 1 as number from master..spt_values where number between 0 and 10
),
temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)
select *, SUBSTRING(abc, number, 2) as S
from temp
	cross join number
where LEN(SUBSTRING(abc, number, 2)) = 2
order by num


автору же не по 2 символа разбить, а на группы одинаковых символов.
31 янв 19, 12:56    [21798699]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
_human
Member

Откуда:
Сообщений: 560
;with temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)

, split_cte as 
(
	select num, abc, c.s, c.r
		, case 
			when s <> lag(s) over(partition by num order by r) 
			then r
		  end as c
	from temp
		cross apply 
		(
			select top (len(abc))
				SUBSTRING(abc, row_number() over(order by (select null)), 1) as s
				,row_number() over(order by (select null)) as r
			from master..spt_values
		) as c
)

, itzik_cte AS
(
  SELECT num, abc, s, r, c,
    MAX( CASE WHEN c IS NOT NULL THEN r END )
  OVER( partition by num ORDER BY r
        ROWS UNBOUNDED PRECEDING ) AS grp
  FROM split_cte
)
SELECT num, s, r, isnull(
  MAX(c) OVER( PARTITION BY num, grp
          ORDER BY r
          ROWS UNBOUNDED PRECEDING ), 0) AS lastval
into #x
FROM itzik_cte;


SELECT num, lastval, (SELECT N'' + s 
  FROM #x AS p2
   WHERE p2.num = p.num 
		AND p2.lastval = p.lastval
   ORDER BY r
   FOR XML PATH(N''))
FROM #x AS p
GROUP BY num, lastval
31 янв 19, 13:40    [21798750]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
swd1986
Member

Откуда: KZ
Сообщений: 36
Ого! Сколько привалило!

Спасибо Вам всем большое! Попробую запилить без create function

На TSQL

msLex
автору же не по 2 символа разбить, а на группы одинаковых символов


Да вы правы, длина групп символов неогранничена

abbbbbbb

Будет теперь как:
a
bbbbbbb

msLex
alexeyvg
пропущено...
Вот даже без CTE, обрабатывайте напильником:
--  Вместо with number/master..spt_values лучше использовать свою таблицу чисел
with number as (
	select distinct number * 2 + 1 as number from master..spt_values where number between 0 and 10
),
temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)
select *, SUBSTRING(abc, number, 2) as S
from temp
	cross join number
where LEN(SUBSTRING(abc, number, 2)) = 2
order by num


автору же не по 2 символа разбить, а на группы одинаковых символов.
31 янв 19, 13:43    [21798754]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
aleks222
Member

Откуда:
Сообщений: 959
Какой ужос.

with n as (	select distinct number as number from master..spt_values where number between 0 and 100)
   , t as (
	        select 1 as num, 'aabbaaa' as abc
	        UNION ALL
	        select 2, 'bbcc'
	        UNION ALL
	        select 3, 'ccdd' 
	        UNION ALL
	        select 4, 'ccee'
          )
    , x as ( select *, n = row_number() over( partition by abc order by number)
               from t inner join n on n.number <= len(abc)
               where SUBSTRING(abc, number, 1) <> SUBSTRING(abc, number + 1, 1) 
           )
    select x1.*, s = SUBSTRING(x1.abc, x1.number + 1, x2.number - x1.number)
      from x as x1 inner join x as x2 on x1.abc = x2.abc and x1.n + 1 = x2.n
      order by abc, x1.Number
-- в версиях поновее можно обойтись LEAD/LAG
31 янв 19, 13:44    [21798756]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
swd1986
Member

Откуда: KZ
Сообщений: 36
aleks222,

Благодарю Вас!
31 янв 19, 13:52    [21798767]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
invm
Member

Откуда: Москва
Сообщений: 9349
aleks222
Какой ужос.
Это ты так свое творение оценил? Картинка с другого сайта.

swd1986
Попробую запилить без create function
Вам шашечки или ехать?
Изучайте и анализируйте:
+
use tempdb;
go

create function dbo.fnSplit
(
 @s varchar(max)
)
returns table
as
return (
 with t(p, c, g) as
 (
  select 1, substring(@s, 1, 1), 1

  union all

  select
   t.p + 1, a.c, case when a.c <> t.c then t.g + 1 else t.g end
  from
   t cross apply
   (select substring(@s, p + 1, 1)) a(c)
  where
   a.c > ''
 )
 select substring(@s, min(p), max(p) - min(p) + 1) as s from t group by g
);
go

create function dbo.splitter (@s varchar(8000))
returns table as
return 
	with spllited as (
		select 
			start_pos = 1 
			,  end_pos = nullif(patindex('%[^' + SUBSTRING(@s, 1, 1) + ']%' , @s ) - 1, 0) 
		union all
		select 
			start_pos = s.end_pos + 1 
			, end_pos = s.end_pos + nullif(patindex ('%[^' + SUBSTRING(RIGHT(@s, len(@s) - s.end_pos), 1, 1) + ']%' , RIGHT(@s, len(@s) - s.end_pos) ), 0) - 1 
		from  spllited s
		where 
			end_pos is not null
	)
	select 
		part = SUBSTRING(@s, start_pos, isnull(end_pos, len(@s)) - start_pos + 1)
		, start_pos
		, end_pos = isnull(end_pos, len(@s))
	from spllited
go

declare @r int = 10;

create table dbo.t (abc varchar(8000));

with temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)
insert into dbo.t
select 
 replicate(t.abc, @r)
from
 (
  select top (5000)
   1
  from
   master.dbo.spt_values a cross join
   master.dbo.spt_values b
 ) x(x) cross join
 temp t;
go

declare @s varchar(8000), @dt datetime2;
declare @results table (description varchar(100), elapsed_time int);

select @dt = sysdatetime();
select
 @s = b.s
from
 dbo.t a cross apply
 dbo.fnSplit(a.abc) b
option
 (maxdop 1, maxrecursion 0);
insert into @results values ('invm', datediff(ms, @dt, sysdatetime()));

select @dt = sysdatetime();
select
 @s = b.part
from
 dbo.t a cross apply
 dbo.splitter(a.abc) b
option
 (maxdop 1, maxrecursion 0);
insert into @results values ('msLex', datediff(ms, @dt, sysdatetime()));

select @dt = sysdatetime();
with n as (	select distinct number as number from master..spt_values where number between 0 and 1000),
x as ( select *, n = row_number() over( partition by abc order by number)
               from dbo.t inner join n on n.number <= len(abc)
               where SUBSTRING(abc, number, 1) <> SUBSTRING(abc, number + 1, 1) 
           )
    select @s = SUBSTRING(x1.abc, x1.number + 1, x2.number - x1.number)
      from x as x1 inner join x as x2 on x1.abc = x2.abc and x1.n + 1 = x2.n
option
 (maxdop 1);
insert into @results values ('aleks222', datediff(ms, @dt, sysdatetime()));

select * from @results order by elapsed_time;
go

drop table dbo.t;
drop function dbo.fnSplit, dbo.splitter;
go

Для @r = 1
descriptionelapsed_time
invm95
msLex301
aleks222317

Для @r = 10
descriptionelapsed_time
invm435
msLex2822
aleks2223906
31 янв 19, 15:06    [21798858]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
swd1986
Member

Откуда: KZ
Сообщений: 36
Как раз сижу изучаю)

invm
aleks222
Какой ужос.
Это ты так свое творение оценил? Картинка с другого сайта.

swd1986
Попробую запилить без create function
Вам шашечки или ехать?
Изучайте и анализируйте:
+
use tempdb;
go

create function dbo.fnSplit
(
 @s varchar(max)
)
returns table
as
return (
 with t(p, c, g) as
 (
  select 1, substring(@s, 1, 1), 1

  union all

  select
   t.p + 1, a.c, case when a.c <> t.c then t.g + 1 else t.g end
  from
   t cross apply
   (select substring(@s, p + 1, 1)) a(c)
  where
   a.c > ''
 )
 select substring(@s, min(p), max(p) - min(p) + 1) as s from t group by g
);
go

create function dbo.splitter (@s varchar(8000))
returns table as
return 
	with spllited as (
		select 
			start_pos = 1 
			,  end_pos = nullif(patindex('%[^' + SUBSTRING(@s, 1, 1) + ']%' , @s ) - 1, 0) 
		union all
		select 
			start_pos = s.end_pos + 1 
			, end_pos = s.end_pos + nullif(patindex ('%[^' + SUBSTRING(RIGHT(@s, len(@s) - s.end_pos), 1, 1) + ']%' , RIGHT(@s, len(@s) - s.end_pos) ), 0) - 1 
		from  spllited s
		where 
			end_pos is not null
	)
	select 
		part = SUBSTRING(@s, start_pos, isnull(end_pos, len(@s)) - start_pos + 1)
		, start_pos
		, end_pos = isnull(end_pos, len(@s))
	from spllited
go

declare @r int = 10;

create table dbo.t (abc varchar(8000));

with temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)
insert into dbo.t
select 
 replicate(t.abc, @r)
from
 (
  select top (5000)
   1
  from
   master.dbo.spt_values a cross join
   master.dbo.spt_values b
 ) x(x) cross join
 temp t;
go

declare @s varchar(8000), @dt datetime2;
declare @results table (description varchar(100), elapsed_time int);

select @dt = sysdatetime();
select
 @s = b.s
from
 dbo.t a cross apply
 dbo.fnSplit(a.abc) b
option
 (maxdop 1, maxrecursion 0);
insert into @results values ('invm', datediff(ms, @dt, sysdatetime()));

select @dt = sysdatetime();
select
 @s = b.part
from
 dbo.t a cross apply
 dbo.splitter(a.abc) b
option
 (maxdop 1, maxrecursion 0);
insert into @results values ('msLex', datediff(ms, @dt, sysdatetime()));

select @dt = sysdatetime();
with n as (	select distinct number as number from master..spt_values where number between 0 and 1000),
x as ( select *, n = row_number() over( partition by abc order by number)
               from dbo.t inner join n on n.number <= len(abc)
               where SUBSTRING(abc, number, 1) <> SUBSTRING(abc, number + 1, 1) 
           )
    select @s = SUBSTRING(x1.abc, x1.number + 1, x2.number - x1.number)
      from x as x1 inner join x as x2 on x1.abc = x2.abc and x1.n + 1 = x2.n
option
 (maxdop 1);
insert into @results values ('aleks222', datediff(ms, @dt, sysdatetime()));

select * from @results order by elapsed_time;
go

drop table dbo.t;
drop function dbo.fnSplit, dbo.splitter;
go

Для @r = 1
descriptiontelapsed_time
invmt95
msLext301
aleks222t317

Для @r = 10
descriptiontelapsed_time
invmt435
msLext2822
aleks222t3906
31 янв 19, 15:28    [21798892]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
swd1986
Member

Откуда: KZ
Сообщений: 36
with n as (	select number = row_number() over(order by 1/0) from utb )
   , t as (
	        select 1 as num, 'aabbaaa' as abc
	        UNION ALL
	        select 2, 'bbccbb'
	        UNION ALL
	        select 3, 'ccdd' 
	        UNION ALL
	        select 4, 'ccee'
          )
    , x as ( select *, n = row_number() over( partition by abc order by number)
               from t inner join n on n.number <= len(abc)
               where SUBSTRING(abc, number, 1) <> SUBSTRING(abc, number + 1, 1) 
           )

    select x1.*, s = SUBSTRING(x1.abc, x1.number + 1, x2.number - x1.number)
    from x as x1 inner join x as x2 on x1.abc = x2.abc and x1.n + 1 = x2.n
    order by abc, x1.Number


num         abc     number               n                    s
----------- ------- -------------------- -------------------- -------
1           aabbaaa 2                    1                    bb
1           aabbaaa 4                    2                    aaa
2           bbccbb  2                    1                    cc
2           bbccbb  4                    2                    bb
3           ccdd    2                    1                    dd
4           ccee    2                    1                    ee


А должно быть:

aa
bb
aaa
bb
cc
bb
cc
dd
cc
ee

А так все понял куда копать

Мои мозги гораздо тормознутее ваших, дайте переварить всю инфу) спасибо!!


aleks222
Какой ужос.

with n as (	select distinct number as number from master..spt_values where number between 0 and 100)
   , t as (
	        select 1 as num, 'aabbaaa' as abc
	        UNION ALL
	        select 2, 'bbcc'
	        UNION ALL
	        select 3, 'ccdd' 
	        UNION ALL
	        select 4, 'ccee'
          )
    , x as ( select *, n = row_number() over( partition by abc order by number)
               from t inner join n on n.number <= len(abc)
               where SUBSTRING(abc, number, 1) <> SUBSTRING(abc, number + 1, 1) 
           )
    select x1.*, s = SUBSTRING(x1.abc, x1.number + 1, x2.number - x1.number)
      from x as x1 inner join x as x2 on x1.abc = x2.abc and x1.n + 1 = x2.n
      order by abc, x1.Number
-- в версиях поновее можно обойтись LEAD/LAG
31 янв 19, 15:31    [21798898]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
aleks222
Member

Откуда:
Сообщений: 959
invm
Изучайте и анализируйте:


Передергиваете, парнишша?

Я понимаю, что выборка из системной таблицы да ишо с distinct - это обосраться и не жить.

Но, ежели, слегка отполировать - будет быстрее, а главное - понятнее.
Чем твое безумное творение.
31 янв 19, 16:53    [21798987]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
aleks222
Member

Откуда:
Сообщений: 959
Нумерки ужо сами сделайте.
with n as (	select distinct number as number from master..spt_values where number between 0 and 100)
   , t as (
	        select 1 as num, 'aabbaaa' as abc
	        UNION ALL
	        select 2, 'bbcc'
	        UNION ALL
	        select 3, 'ccdd' 
	        UNION ALL
	        select 4, 'ccee'
          )
    , x0 as ( select * from t inner join n on n.number <= len(abc) where SUBSTRING(abc, number, 1) <> SUBSTRING(abc, number + 1, 1) )
	, x as ( select *, nNumber = lead(number) over(partition by abc order by number) from x0 )
    select x.*, s = SUBSTRING(x.abc, x.number + 1, x.nNumber - x.number)
      from x 
	  where nNumber is not null
      order by abc, number
;
31 янв 19, 17:10    [21799006]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
invm
Member

Откуда: Москва
Сообщений: 9349
aleks222
Но, ежели, слегка отполировать - будет быстрее
+ Отполированное
use tempdb;
go

create table dbo.Numbers (number int not null primary key);
insert into dbo.Numbers
select top (100000)
 row_number() over (order by (select 1))
from
 master.dbo.spt_values a cross join
 master.dbo.spt_values b;
go

create function dbo.fnSplit
(
 @s varchar(max)
)
returns table
as
return (
 with t(p, c, g) as
 (
  select 1, substring(@s, 1, 1), 1

  union all

  select
   t.p + 1, a.c, case when a.c <> t.c then t.g + 1 else t.g end
  from
   t cross apply
   (select substring(@s, p + 1, 1)) a(c)
  where
   a.c > ''
 )
 select substring(@s, min(p), max(p) - min(p) + 1) as s from t group by g
);
go

create function dbo.splitter (@s varchar(8000))
returns table as
return 
	with spllited as (
		select 
			start_pos = 1 
			,  end_pos = nullif(patindex('%[^' + SUBSTRING(@s, 1, 1) + ']%' , @s ) - 1, 0) 
		union all
		select 
			start_pos = s.end_pos + 1 
			, end_pos = s.end_pos + nullif(patindex ('%[^' + SUBSTRING(RIGHT(@s, len(@s) - s.end_pos), 1, 1) + ']%' , RIGHT(@s, len(@s) - s.end_pos) ), 0) - 1 
		from  spllited s
		where 
			end_pos is not null
	)
	select 
		part = SUBSTRING(@s, start_pos, isnull(end_pos, len(@s)) - start_pos + 1)
		, start_pos
		, end_pos = isnull(end_pos, len(@s))
	from spllited
go

declare @r int = 10;

create table dbo.t (num int, abc varchar(8000), row_id int identity, primary key (num, row_id));

with temp as (
	select 1 as num, 'aabbaaa' as abc
	UNION ALL
	select 2, 'bbcc'
	UNION ALL
	select 3, 'ccdd' 
	UNION ALL
	select 4, 'ccee'
)
insert into dbo.t
 (num, abc)
select 
 num + x.rn * 100, replicate(t.abc, @r)
from
 (
  select top (5000)
   row_number() over (order by (select 1))
  from
   master.dbo.spt_values a cross join
   master.dbo.spt_values b
 ) x(rn) cross join
 temp t;
go

declare @s varchar(8000), @dt datetime2;
declare @results table (description varchar(100), elapsed_time int);

select @dt = sysdatetime();
select
 @s = b.s
from
 dbo.t a cross apply
 dbo.fnSplit(a.abc) b
option
 (maxdop 1, maxrecursion 0);
insert into @results values ('invm', datediff(ms, @dt, sysdatetime()));

select @dt = sysdatetime();
select
 @s = b.part
from
 dbo.t a cross apply
 dbo.splitter(a.abc) b
option
 (maxdop 1, maxrecursion 0);
insert into @results values ('msLex', datediff(ms, @dt, sysdatetime()));

select @dt = sysdatetime();
with x as ( select *, n = row_number() over( partition by num order by number)
               from dbo.t inner join dbo.Numbers n on n.number <= len(abc)
               where SUBSTRING(abc, number, 1) <> SUBSTRING(abc, number + 1, 1) 
           )
    select @s = SUBSTRING(x1.abc, x1.number + 1, x2.number - x1.number)
      from x as x1 inner join x as x2 on x1.num = x2.num and x1.n + 1 = x2.n
option
 (maxdop 1);
insert into @results values ('aleks222, отполировано', datediff(ms, @dt, sysdatetime()));

select @dt = sysdatetime();
with x0 as ( select * from dbo.t t inner join dbo.Numbers n on n.number <= len(t.abc) where SUBSTRING(t.abc, n.number, 1) <> SUBSTRING(t.abc, n.number + 1, 1) )
	, x as ( select *, nNumber = lead(number) over(partition by num order by number) from x0 )
    select @s = SUBSTRING(x.abc, x.number + 1, x.nNumber - x.number)
      from x 
	  where x.nNumber is not null
option
 (maxdop 1);
insert into @results values ('aleks222, отполировано №2', datediff(ms, @dt, sysdatetime()));

select * from @results order by elapsed_time;
go

drop table dbo.Numbers, dbo.t;
drop function dbo.fnSplit, dbo.splitter;
go

Для @r = 1
descriptionelapsed_time
invm68
aleks222, отполировано163
aleks222, отполировано №2196
msLex421

Для @r = 10
descriptionelapsed_time
invm385
aleks222, отполировано №2951
aleks222, отполировано1585
msLex4100

Полируй дальше. Может в процессе даже осознаешь из-за чего твое гениальное творение таки медленнее моего безумного.
31 янв 19, 17:51    [21799056]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
aleks222
Member

Откуда:
Сообщений: 959
invm
Отполированное
Полируй дальше. Может в процессе даже осознаешь из-за чего твое гениальное творение таки медленнее моего безумного.


Полировать то у тя тоже слабо получается.
Твое безумное творение быстрее только на очень длинных строках.

Ты даже свои безумные функции пишешь безумно сложно

alter function dbo.fnSplit( @s varchar(8000) )
returns table
as
return (

	 with t as
	 (
	  select n1 = 1, n2 = nullif( patindex( '%[^' + substring(@s, 1, 1) + ']%', @s ), 0 )
	  union all
	  select n1 = n2, n2 = n2 + nullif( patindex( '%[^' + substring(@s, n2, 1) + ']%', right(@s, len(@s) - n2 + 1 ) ), 0) - 1 from t where n2 is not null
	 )
	 select n1, s = substring( @s, n1, isnull( n2, len(@s) + 1 ) - n1 ) from t
)
;
31 янв 19, 19:11    [21799106]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
invm
Member

Откуда: Москва
Сообщений: 9349
aleks222
Полировать то у тя тоже слабо получается.
Твое безумное творение быстрее только на очень длинных строках.
Ты, дарагуля, глазки все-таки протри и поизучай пример - а то так и продолжишь выставлять себя идиотом. Впрочем, очень похоже, что это твое любимое занятие Картинка с другого сайта.
Заодно там же увидишь все "плюсы" использования patindex...

Ну и исправь свои "гениальные" варианты - они теряет ровно одну строку результата для каждого abc.
31 янв 19, 19:24    [21799120]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
PizzaPizza
Member

Откуда:
Сообщений: 370
Боже боже. Как представлю, с какими продуктами жизнедеятельности вместо данных приходится людям работать, прям слезы на глазах.
Но зато опыт копания в вот этом всем.

Товарищ автор задачи, ответ на вашу задачу находится в любом яп, кроме SQL. Это будет а) быстрее б) удобнее с) короче.
1 фев 19, 04:38    [21799247]     Ответить | Цитировать Сообщить модератору
 Re: Разбить строку на подстроку  [new]
Владислав Колосов
Member

Откуда:
Сообщений: 7762
swd1986,

используй то, что под рукою и не ищи себе другое? (с) Инструменты должны работать по назначению, в том числе и задача обработки строк решается не при помощи SQL Server.
1 фев 19, 12:53    [21799576]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить