powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Помогите написать запрос
12 сообщений из 12, страница 1 из 1
Помогите написать запрос
    #39562766
rsolanov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Добрый вечер.
как из строки
\ext_bulk_insert\[2]\product_layout\loop\[1]\delete ext
получить две строки:
\ext_bulk_insert\[2]
\ext_bulk_insert\[2]\product_layout\loop\[1]

Реализовал следующим образом:
Код: 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.
;with dat as
(
select 
	value,
	ROW_NUMBER() over (order by 1/0) as rn
from
	string_split('\ext_bulk_insert\[2]\product_layout\loop\[1]\delete ext', ']')
where
	value like '%[[]%'
)
, cte as
(
	select
		cast(value + ']' as nvarchar(255)) as value,
		rn
	from
		dat
	where
		rn = 1
	union all
	select
		cast(cte.value + ']' + dat.value + ']' as nvarchar(255)) as value,
		cte.rn + 1 as rn
	from
			cte
		inner join dat on
			cte.rn + 1 = dat.rn
)
select * from cte


Но можно ли как то реализовать проще? (может попробовать использование регулярных выражений на основе clr-функций)
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39562794
скт
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
rsolanov,

Размножить таблицу на 2, и через charindex разбить строки?
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39562798
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Код: sql
1.
2.
DECLARE @S VARCHAR(100)='\ext_bulk_insert\[2]\product_layout\loop\[1]\delete ext';
SELECT LEFT(@S,CHARINDEX(']',@S)),LEFT(@S,CHARINDEX(']',@S,CHARINDEX(']',@S)+1));
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563240
rsolanov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
iap
Код: sql
1.
2.
DECLARE @S VARCHAR(100)='\ext_bulk_insert\[2]\product_layout\loop\[1]\delete ext';
SELECT LEFT(@S,CHARINDEX(']',@S)),LEFT(@S,CHARINDEX(']',@S,CHARINDEX(']',@S)+1));

Здравствуйте, jap. Вижу что не в полном объеме сделал описание задачи: число квадратных скобок всегда неопределенное.
То есть если строка будет следующего вида: DECLARE @S VARCHAR(100)='\ext_bulk_insert\[2]\product\[5]\product_layout\loop\[1]\delete ext';
В таком случае результат должен быть следующим:
\ext_bulk_insert\[2]
\ext_bulk_insert\[2]\product\[5]
\ext_bulk_insert\[2]\product\[5]\product_layout\loop\[1]
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563260
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rsolanov,

Для SQL Server 2016
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
declare @s varchar(100)='\ext_bulk_insert\[2]\product\[5]\product_layout\loop\[1]\delete ext';

declare @pieces table (i int identity primary key, p varchar(100), is_bracketed_number bit);

insert into @pieces
 (p, is_bracketed_number)
 select
  value,
  case when value not like '[%[^0123456789]%]' then 0 else 1 end
 from
  string_split(@s, '\')
 where
  value > '';

select
 b.x.value('.', 'varchar(100)')
from
 (select i from @pieces where is_bracketed_number = 1) a cross apply
 (select '\' + p from @pieces where i <= a.i order by i for xml path(''), type) b(x);


Для других версий ищите на форуме или гуглите любую функцию разбиения стоки по разделителю.
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563303
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rsolanovЗдравствуйте, jap. Вижу что не в полном объеме сделал описание задачи: число квадратных скобок всегда неопределенное.Привет!
Но первая буква не j, а i

Если сделать рекурсивное CTE, ищущее вхождение в строку правой квадратной скобки,
то на каждом следующем шаге можно искать функцией CHARINDEX с третьим параметром,
равным позиции, найденной на предыдущем шаге, плюс 1.
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563621
rsolanov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
iap, действительно запрос получился более оптимальный:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
declare @s varchar(100)='\ext_bulk_insert\[2]\product\[5]\product_layout\loop\[1]\delete ext';

;with
cte as
(
	select
		left(@s, dat.i) as value,
		dat.i as i
	from
		(select CHARINDEX(']', @s) as i) as dat
	union all
	select
		left(@s, dat.i) as value,
		dat.i
	from
		(select CHARINDEX(']', @s, cte.i + 1) as i from cte) as dat
	where
		dat.i > 0
)
select * from cte
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563634
iap
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rsolanov,

можно обойтись и без рекурсии, если задействовать таблицу с достаточно большим количеством строк.
Даже если в ней не будет поля с непрерывным рядом целых чисел, строки можно пронумеровать ROW_NUMBER()ом
и для каждой строки взять n-й символ исходной строки, после чего числа нумерации для строк с правой
квадртной скобкой дадут второй параметр функции LEFT().
Всё это оформить подзапросами или эквивалентными не рекурсивными CTE.
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563736
rsolanov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
iaprsolanov,

можно обойтись и без рекурсии, если задействовать таблицу с достаточно большим количеством строк.
Даже если в ней не будет поля с непрерывным рядом целых чисел, строки можно пронумеровать ROW_NUMBER()ом
и для каждой строки взять n-й символ исходной строки, после чего числа нумерации для строк с правой
квадртной скобкой дадут второй параметр функции LEFT().
Всё это оформить подзапросами или эквивалентными не рекурсивными CTE.Не понял вашу мысль, изначально ведь строка одна, поясните пожалуйста если не сложно предложенный вами алгоритм подробнее
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563761
Руслан Дамирович
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rsolanov,
Как-нибудь вот так
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
DECLARE @s VARCHAR(200) = '\ext_bulk_insert\[2]\product\[5]\product_layout\loop\[1]\delete ext'
;
WITH
[nn] AS (
  SELECT
    [rn]
  FROM
    ( SELECT [rn] = ROW_NUMBER() OVER ( ORDER BY 1/0 ) FROM master..spt_values ) t
  WHERE
    [rn] <= LEN( @s )
)
SELECT
  [value] = LEFT( @s, [rn] ),
  [i] = [rn]
FROM
  [nn]
WHERE
  SUBSTRING( @s, [rn], 1 ) = ']'
;
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39563833
invm
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
rsolanov,

Вот вам для размышлений на тему парсинга строк предложенными выше способами:
Тест
Код: 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.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
use tempdb;
go

create function dbo.fnSplitString
(
 @s nvarchar(max),
 @delimeter nvarchar(100) = N','
)
returns table
as
return (
 with s as
 (
  select
   c.d, d.s
  from
   (select N'[' + @delimeter + N']') a(d) cross apply
   (select replace(@s, @delimeter, a.d)) b(s) cross apply
   (select cast(cast('' as xml).query('sql:column("a.d")') as varchar(max))) c(d) cross apply
   (select cast(cast('' as xml).query('sql:column("b.s")') as varchar(max))) d(s)
 )
 select
  row_number() over (order by (select 1)) as ValueOrder,
  b.n.value('.', 'nvarchar(max)') as Value
 from
  (select cast(N'<item>' + replace(s.s, s.d, N'</item><item>') + N'</item>' as xml) from s) a(x) cross apply
  a.x.nodes('/item') b(n)
);
go

create function dbo.fn1
(
 @s VARCHAR(200)
)
returns table
as
return (
WITH
[nn] AS (
  SELECT
    [rn]
  FROM
    ( SELECT [rn] = ROW_NUMBER() OVER ( ORDER BY 1/0 ) FROM master..spt_values ) t
  WHERE
    [rn] <= LEN( @s )
)
SELECT
  [value] = LEFT( @s, [rn] )
FROM
  [nn]
WHERE
  SUBSTRING( @s, [rn], 1 ) = ']'
);
go

create function dbo.fn2
(
 @s VARCHAR(200)
)
returns table
as
return (
with
cte as
(
	select
		left(@s, dat.i) as value,
		dat.i as i
	from
		(select CHARINDEX(']', @s) as i) as dat
	union all
	select
		left(@s, dat.i) as value,
		dat.i
	from
		(select CHARINDEX(']', @s, cte.i + 1) as i from cte) as dat
	where
		dat.i > 0
)
select value from cte
)
go

create function dbo.fn3
(
 @s VARCHAR(200)
)
returns table
as
return (
 with t(i, p, is_bracketed_number) as
 (
  select
   ValueOrder,
   value,
   case when value like '![%!]' escape '!' then 1 else 0 end
  from
   dbo.fnSplitString(@s, '\')
  where
   value > ''
 )
 select
  b.x.value('.', 'varchar(100)') as value
 from
  (select i from t where is_bracketed_number = 1) a cross apply
  (select '\' + p from t where i <= a.i order by i for xml path(''), type) b(x)
);
go

declare @s varchar(200)	= '\ext_bulk_insert\[2]\product\[5]\product_layout\loop\[1]\delete ext';

create table dbo.t (id int identity primary key, s varchar(200));

insert into dbo.t
select top (1000000)
 @s
from
 master.dbo.spt_values a cross join
 master.dbo.spt_values b;
go

declare @c int;

set statistics time on;

select
 @c = count(*)
from
 dbo.t cross apply
 dbo.fn1(s) f
option
 (maxdop 1);

select
 @c = count(*)
from
 dbo.t cross apply
 dbo.fn2(s) f
option
 (maxdop 1);

select
 @c = count(*)
from
 dbo.t cross apply
 dbo.fn3(s) f
option
 (maxdop 1);

set statistics time off;
go

drop table dbo.t;
drop function dbo.fn1, dbo.fn2, dbo.fn3, dbo.fnSplitString;
go

Результат
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
(1000000 rows affected)

 Время работы SQL Server:
   Время ЦП = 22917 мс, затраченное время = 23102 мс.

 Время работы SQL Server:
   Время ЦП = 47689 мс, затраченное время = 48765 мс.

 Время работы SQL Server:
   Время ЦП = 1248 мс, затраченное время = 1249 мс.
...
Рейтинг: 0 / 0
Помогите написать запрос
    #39564555
rsolanov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
invm, большое вам спасибо за такое исследование. Вот уж не думал что dbo.fn3 окажется самым быстрым способом на больших объемах данных.
...
Рейтинг: 0 / 0
12 сообщений из 12, страница 1 из 1
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Помогите написать запрос
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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