Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Помогите написать запрос / 12 сообщений из 12, страница 1 из 1
01.12.2017, 17:37:50
    #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
01.12.2017, 18:13:57
    #39562794
скт
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите написать запрос
rsolanov,

Размножить таблицу на 2, и через charindex разбить строки?
...
Рейтинг: 0 / 0
01.12.2017, 18:22:55
    #39562798
iap
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
03.12.2017, 12:56:10
    #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
03.12.2017, 14:15:30
    #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
03.12.2017, 16:59:03
    #39563303
iap
iap
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите написать запрос
rsolanovЗдравствуйте, jap. Вижу что не в полном объеме сделал описание задачи: число квадратных скобок всегда неопределенное.Привет!
Но первая буква не j, а i

Если сделать рекурсивное CTE, ищущее вхождение в строку правой квадратной скобки,
то на каждом следующем шаге можно искать функцией CHARINDEX с третьим параметром,
равным позиции, найденной на предыдущем шаге, плюс 1.
...
Рейтинг: 0 / 0
04.12.2017, 12:48:45
    #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
04.12.2017, 13:05:38
    #39563634
iap
iap
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите написать запрос
rsolanov,

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

можно обойтись и без рекурсии, если задействовать таблицу с достаточно большим количеством строк.
Даже если в ней не будет поля с непрерывным рядом целых чисел, строки можно пронумеровать ROW_NUMBER()ом
и для каждой строки взять n-й символ исходной строки, после чего числа нумерации для строк с правой
квадртной скобкой дадут второй параметр функции LEFT().
Всё это оформить подзапросами или эквивалентными не рекурсивными CTE.Не понял вашу мысль, изначально ведь строка одна, поясните пожалуйста если не сложно предложенный вами алгоритм подробнее
...
Рейтинг: 0 / 0
04.12.2017, 14:58:27
    #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
04.12.2017, 15:49:45
    #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
05.12.2017, 16:35:49
    #39564555
rsolanov
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Помогите написать запрос
invm, большое вам спасибо за такое исследование. Вот уж не думал что dbo.fn3 окажется самым быстрым способом на больших объемах данных.
...
Рейтинг: 0 / 0
Форумы / Microsoft SQL Server [игнор отключен] [закрыт для гостей] / Помогите написать запрос / 12 сообщений из 12, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


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