Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Разбить строку на подстроку / 19 сообщений из 19, страница 1 из 1
31.01.2019, 11:48
    #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
31.01.2019, 12:21
    #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
31.01.2019, 12:23
    #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
31.01.2019, 12:27
    #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
31.01.2019, 12:56
    #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
31.01.2019, 13:40
    #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
31.01.2019, 13:43
    #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
31.01.2019, 13:44
    #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
31.01.2019, 13:52
    #39767588
swd1986
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разбить строку на подстроку
aleks222,

Благодарю Вас!
...
Рейтинг: 0 / 0
31.01.2019, 15:06
    #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
31.01.2019, 15:28
    #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
31.01.2019, 15:31
    #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
31.01.2019, 16:53
    #39767715
aleks222
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разбить строку на подстроку
invmИзучайте и анализируйте:

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

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

Но, ежели, слегка отполировать - будет быстрее, а главное - понятнее.
Чем твое безумное творение.
...
Рейтинг: 0 / 0
31.01.2019, 17:10
    #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
31.01.2019, 17:51
    #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
31.01.2019, 19:11
    #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
31.01.2019, 19:24
    #39767803
invm
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Разбить строку на подстроку
aleks222Полировать то у тя тоже слабо получается.
Твое безумное творение быстрее только на очень длинных строках.Ты, дарагуля, глазки все-таки протри и поизучай пример - а то так и продолжишь выставлять себя идиотом. Впрочем, очень похоже, что это твое любимое занятие

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

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

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

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


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