powered by simpleCommunicator - 2.0.60     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Разбить строку на подстроку
19 сообщений из 19, страница 1 из 1
Разбить строку на подстроку
    #39767481
swd1986
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Всем привет! И <многопивавсем>!

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

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
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'
),



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

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
1	aa
1	bb
1	aaa
2	bb
2	cc
3	cc
3	dd
4	cc
4	ee



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

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
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 я прочитал в первую очередь, не пинайте ))
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767509
msLex
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Если честно, то такие задачи прямо предназначены для CLR функций, но если совсем хочется на TSQL

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
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)
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767512
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
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
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767516
Фотография alexeyvg
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
swd1986На простом чистом sql или cte это как то можно реализовать?Вот даже без CTE, обрабатывайте напильником:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
--  Вместо 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
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767550
msLex
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
alexeyvgswd1986На простом чистом sql или cte это как то можно реализовать?Вот даже без CTE, обрабатывайте напильником:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
--  Вместо 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 символа разбить, а на группы одинаковых символов.
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767581
_human
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
;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
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767583
swd1986
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Ого! Сколько привалило!

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

На TSQL

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

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

abbbbbbb

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

msLexalexeyvgпропущено...
Вот даже без CTE, обрабатывайте напильником:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
--  Вместо 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 символа разбить, а на группы одинаковых символов.
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767584
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Какой ужос.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
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
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767588
swd1986
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
aleks222,

Благодарю Вас!
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767648
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks222Какой ужос.Это ты так свое творение оценил?


swd1986Попробую запилить без create functionВам шашечки или ехать?
Изучайте и анализируйте:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
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 = 1descriptionelapsed_timeinvm95msLex301aleks222317

Для @r = 10descriptionelapsed_timeinvm435msLex2822aleks2223906
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767671
swd1986
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Как раз сижу изучаю)

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


swd1986Попробую запилить без create functionВам шашечки или ехать?
Изучайте и анализируйте:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
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 = 1descriptiontelapsed_timeinvmt95msLext301aleks222t317

Для @r = 10descriptiontelapsed_timeinvmt435msLext2822aleks222t3906
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767673
swd1986
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
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



Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
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Какой ужос.

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
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
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767715
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
invmИзучайте и анализируйте:

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

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

Но, ежели, слегка отполировать - будет быстрее, а главное - понятнее.
Чем твое безумное творение.
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767728
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Нумерки ужо сами сделайте.
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
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
;
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767759
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks222Но, ежели, слегка отполировать - будет быстрее
Отполированное
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
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 = 1descriptionelapsed_timeinvm68aleks222, отполировано163aleks222, отполировано №2196msLex421

Для @r = 10descriptionelapsed_timeinvm385aleks222, отполировано №2951aleks222, отполировано1585msLex4100
Полируй дальше. Может в процессе даже осознаешь из-за чего твое гениальное творение таки медленнее моего безумного.
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767794
aleks222
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
invm Отполированное
Полируй дальше. Может в процессе даже осознаешь из-за чего твое гениальное творение таки медленнее моего безумного.

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

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

Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
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
)
;
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767803
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
aleks222Полировать то у тя тоже слабо получается.
Твое безумное творение быстрее только на очень длинных строках.Ты, дарагуля, глазки все-таки протри и поизучай пример - а то так и продолжишь выставлять себя идиотом. Впрочем, очень похоже, что это твое любимое занятие

Заодно там же увидишь все "плюсы" использования patindex...

Ну и исправь свои "гениальные" варианты - они теряет ровно одну строку результата для каждого abc.
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39767860
PizzaPizza
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Боже боже. Как представлю, с какими продуктами жизнедеятельности вместо данных приходится людям работать, прям слезы на глазах.
Но зато опыт копания в вот этом всем.

Товарищ автор задачи, ответ на вашу задачу находится в любом яп, кроме SQL. Это будет а) быстрее б) удобнее с) короче.
...
Рейтинг: 0 / 0
Разбить строку на подстроку
    #39768103
Владислав Колосов
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
swd1986,

используй то, что под рукою и не ищи себе другое? (с) Инструменты должны работать по назначению, в том числе и задача обработки строк решается не при помощи SQL Server.
...
Рейтинг: 0 / 0
19 сообщений из 19, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Разбить строку на подстроку
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]