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

Откуда: Раменское
Сообщений: 52
Ребят, такой вопрос. Как можно разбить по полям данный текст.

01. Книга\01.01. Абзац\01.01.01. Строка

Должно получится примерно так:
Столбец 1 |__Столбец 2_| ___ Столбец 3 __|
01. Книга | 01.01. Абзац | 01.01.01. Строка |


Понятно, что разбивку можно сделать по данному ' \ ' символу. Попробовал
CHARINDEX
, получилось обрезать только до первого " \ "
11 фев 13, 11:39    [13907424]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
_djХомяГ
Guest
CHARINDEX + рекурсивное CTE
11 фев 13, 11:41    [13907429]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Гость333
Member

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

declare @s varchar(8000);
set @s = '01. Книга\01.01. Абзац\01.01.01. Строка';
select [Столбец 1] = left(@s, charindex('\', @s) - 1),
       [Столбец 2] = substring(@s, charindex('\', @s) + 1, charindex('\', @s, charindex('\', @s) + 1) - charindex('\', @s) - 1),
       [Столбец 3] = substring(@s, charindex('\', @s, charindex('\', @s) + 1) + 1, 8000);
11 фев 13, 11:50    [13907507]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
_djХомяГ
Guest
Или с помощью динамики так
11 фев 13, 11:51    [13907509]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
_djХомяГ
Guest
Если кол-во образующихся полей <=3 то можно использовать PARSENAME
например так
11 фев 13, 11:56    [13907543]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
Гость333
Mitresky,

declare @s varchar(8000);
set @s = '01. Книга\01.01. Абзац\01.01.01. Строка';
select [Столбец 1] = left(@s, charindex('\', @s) - 1),
       [Столбец 2] = substring(@s, charindex('\', @s) + 1, charindex('\', @s, charindex('\', @s) + 1) - charindex('\', @s) - 1),
       [Столбец 3] = substring(@s, charindex('\', @s, charindex('\', @s) + 1) + 1, 8000);



А если неизвестная строка? Не '01. Книга\01.01. Абзац\01.01.01. Строка', а какая-нить другая, к примеру 'Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово'. То есть может быть множество подстрок.
11 фев 13, 12:20    [13907708]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
qwerty112
Guest
Mitresky
А если неизвестная строка? Не '01. Книга\01.01. Абзац\01.01.01. Строка', а какая-нить другая, к примеру 'Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово'. То есть может быть множество подстрок.

и что ты будеш делать с неизвестным количеством столбцов ?
11 фев 13, 12:32    [13907795]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
qwerty112
Mitresky
А если неизвестная строка? Не '01. Книга\01.01. Абзац\01.01.01. Строка', а какая-нить другая, к примеру 'Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово'. То есть может быть множество подстрок.

и что ты будеш делать с неизвестным количеством столбцов ?


Мне нужно просто вывести их и всё. Если 3 параметра, то выводит 3, если 4, то 4..
11 фев 13, 12:35    [13907814]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31430
Mitresky
А если неизвестная строка? Не '01. Книга\01.01. Абзац\01.01.01. Строка', а какая-нить другая, к примеру 'Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово'. То есть может быть множество подстрок.
Тогда нужно формировать динамический SQL, либо делать строки с запасом (то есть всегда будут выводиться к примеру 100 столбцов, но часть правых будут пустые)
11 фев 13, 12:38    [13907840]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Гость333
Member

Откуда:
Сообщений: 3683
Mitresky
Мне нужно просто вывести их и всё. Если 3 параметра, то выводит 3, если 4, то 4..

Куда вывести? В каком виде? Как должны называться столбцы (слабо верится, что "Столбец 1" ... "Столбец N")?
Формулируйте задачу до конца, чо уж там.
11 фев 13, 12:46    [13907912]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
Хорошо, если так!. Что число столбцов должно быть только 4, если строка больше 4 параметров, то мы обрезаем их до 4 и выводим по столбцам.
11 фев 13, 12:48    [13907932]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
_ч_
Member

Откуда:
Сообщений: 1427
Mitresky
Гость333
Mitresky,

declare @s varchar(8000);
set @s = '01. Книга\01.01. Абзац\01.01.01. Строка';
select [Столбец 1] = left(@s, charindex('\', @s) - 1),
       [Столбец 2] = substring(@s, charindex('\', @s) + 1, charindex('\', @s, charindex('\', @s) + 1) - charindex('\', @s) - 1),
       [Столбец 3] = substring(@s, charindex('\', @s, charindex('\', @s) + 1) + 1, 8000);



А если неизвестная строка? Не '01. Книга\01.01. Абзац\01.01.01. Строка', а какая-нить другая, к примеру 'Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово'. То есть может быть множество подстрок.


Придется Вам сделать ограничение на кол-во столбцов.
11 фев 13, 12:49    [13907948]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Glory
Member

Откуда:
Сообщений: 104760
Mitresky
Мне нужно просто вывести их и всё. Если 3 параметра, то выводит 3, если 4, то 4..

Интересно, а чем принципиально _вывод_
01. Книга\01.01. Абзац\01.01.01. Строка
отличается от
01. Книга | 01.01. Абзац | 01.01.01. Строка |
???
11 фев 13, 12:53    [13907981]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
_djХомяГ
Guest
Mitresky
Хорошо, если так!. Что число столбцов должно быть только 4, если строка больше 4 параметров, то мы обрезаем их до 4 и выводим по столбцам.

И в чем проблема - используйте любой вышеуказанный метод кроме PARSENAME в решении Гость333 добавьте логику для 4 столбца по аналогии
11 фев 13, 12:55    [13908009]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
qwerty112
Guest
Mitresky
Хорошо, если так!. Что число столбцов должно быть только 4, если строка больше 4 параметров, то мы обрезаем их до 4 и выводим по столбцам.

declare @t table (txt varchar(60))

insert into @t

select '01. Книга\01.01. Абзац\01.01.01. Строка' union all
select 'Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово'

;with cte as
(select txt, cast('<a>'+replace(txt,'\','</a><a>')+'</a>' as xml) as xtxt from @t)

select txt, [1], [2], [3], [4] --, [5], ..., [100500]
from

(select cte.txt, tt.val, row_number() over(partition by txt order by charindex(tt.val, cte.txt)) as num
from cte 
cross apply 
	(select t.c.value('text()[1]', 'varchar(20)') as [val]
	from cte.xtxt.nodes('/a') as t(c)) tt) a

pivot (max(val) for num in ([1], [2], [3], [4] /*, [5], ..., [100500] */)) pvt

(2 row(s) affected)
txt                                                          1                    2                    3                    4
------------------------------------------------------------ -------------------- -------------------- -------------------- --------------------
01. Книга\01.01. Абзац\01.01.01. Строка                      01. Книга            01.01. Абзац         01.01.01. Строка     NULL
Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово       Книга                01.01. Абзац         01.01.01. Строка     01.01.01.01. Слово

(2 row(s) affected)

только будет "беда", если могут быть одинаковые "элементы" в "разбиваемой" строке
11 фев 13, 12:58    [13908043]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
Glory
Mitresky
Мне нужно просто вывести их и всё. Если 3 параметра, то выводит 3, если 4, то 4..

Интересно, а чем принципиально _вывод_
01. Книга\01.01. Абзац\01.01.01. Строка
отличается от
01. Книга | 01.01. Абзац | 01.01.01. Строка |
???


Это я просто столбцы обрисовал, а не символ.
11 фев 13, 13:00    [13908057]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Glory
Member

Откуда:
Сообщений: 104760
Mitresky
Это я просто столбцы обрисовал, а не символ.

Ну и зачем для _вывода_ нужны отдельные столбцы ?
11 фев 13, 13:02    [13908077]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
qwerty112,

Буду думать дальше, если что, отпишусь..
11 фев 13, 13:03    [13908090]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
Glory
Mitresky
Это я просто столбцы обрисовал, а не символ.

Ну и зачем для _вывода_ нужны отдельные столбцы ?


Желание заказчика
11 фев 13, 13:04    [13908098]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
Кому интересно. Сделал так! Создал 2 функции: Одно убирает слова после символа, а вторая до.
CREATE FUNCTION [dbo].[BeforeFirst]
(
		 @p varchar(max) -- строка
		 ,@s char           -- символ
)
RETURNS varchar(8000)
AS
BEGIN
		 DECLARE @result varchar(8000)
		 SET @result = CAST( (LEFT(@p+@s,CHARINDEX(@s,@p+@s)-1)) AS varchar(8000))
		 RETURN @result
END
GO

и
CREATE FUNCTION [dbo].[AfterFirst]
(
		 @p varchar(max)
		 ,@s char
)
RETURNS varchar(8000)
AS
BEGIN
		 DECLARE @result varchar(8000)
		 IF CHARINDEX(@s,@p) > 0
		 		 SET @result = CAST(RIGHT(@p,LEN(@p)-CHARINDEX(@s,@p)) AS varchar(8000))
		 ELSE
		 		 SET @result = ' '
		 RETURN @result
END

GO


ну и сам запрос:

SELECT 
 CAST (dbo.BeforeFirst(A.Поле,'\') AS VARCHAR(128))AS 'Книга'
,CAST ((dbo.BeforeFirst((dbo.AfterFirst(A.Поле,'\')),'\'))AS VARCHAR(128)) AS 'Абзац'
,CAST ((dbo.BeforeFirst((dbo.AfterFirst((dbo.AfterFirst(A.Поле,'\')),'\')),'\'))AS VARCHAR(128)) AS 'Строка'
,CAST ((dbo.BeforeFirst((dbo.AfterFirst((dbo.AfterFirst((dbo.AfterFirst(A.Поле,'\')),'\')),'\')),'\'))AS VARCHAR(128)) AS 'Слово'
FROM таблица A WITH(NOLOCK)
WHERE A.Поле !=' ' AND A.Поле IS NOT NULL
11 фев 13, 16:36    [13909860]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
iap
Member

Откуда: Москва
Сообщений: 46999
Mitresky,

скалярные UDF + VARCHAR(MAX) - это знатный тормоз, однако!
11 фев 13, 16:48    [13909945]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Гость333
Member

Откуда:
Сообщений: 3683
Mitresky
Кому интересно. Сделал так! Создал 2 функции

Ждём вас обратно с темой "запрос нормально работает на сотне записей, но тормозит на десятках тысяч".
11 фев 13, 16:50    [13909957]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Glory
Member

Откуда:
Сообщений: 104760
Mitresky
Кому интересно. Сделал так! Создал 2 функции: Одно убирает слова после символа, а вторая до.

Возьмите одну и сотен готовых функций парсига текстовой строки по разделителю
Получите с ее помощью таблицу
Потом возьмите опять же одну из сотен процедур для создания crosstab/"шахматки" с произвольным количеством столбцов
11 фев 13, 17:02    [13910052]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Mitresky
Member

Откуда: Раменское
Сообщений: 52
Гость333
Mitresky
Кому интересно. Сделал так! Создал 2 функции

Ждём вас обратно с темой "запрос нормально работает на сотне записей, но тормозит на десятках тысяч".


В данной выборке будут динамические параметры и много условий отбора и поэтому записей на выходе будет не больше 10-15. А на счет тормозов да, буду дальше оптимизировать код, ну и так далее..
12 фев 13, 09:10    [13911916]     Ответить | Цитировать Сообщить модератору
 Re: разбивка текста  [new]
Гость333
Member

Откуда:
Сообщений: 3683
Mitresky
Гость333
Ждём вас обратно с темой "запрос нормально работает на сотне записей, но тормозит на десятках тысяч".


В данной выборке будут динамические параметры и много условий отбора и поэтому записей на выходе будет не больше 10-15. А на счет тормозов да, буду дальше оптимизировать код, ну и так далее..

Проверил ваш вариант на 100 тыс. записей вида '01. Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово'. Выполнилось за 12 секунд (локальная машина, Core i5). Удивлён, честно :-) Я думал, гораздо всё печальнее будет.

Вот держите вариант, который работал 4 секунды на тех же 100 тыс. записей:
create table #таблица (Поле varchar(1000));

insert #таблица values('01. Книга');
insert #таблица values('01. Книга\');
insert #таблица values('01. Книга\01.01. Абзац');
insert #таблица values('01. Книга\01.01. Абзац\01.01.01. Строка');
insert #таблица values('01. Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово');
insert #таблица values('01. Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово\01.01.01.01.01. Дело');
insert #таблица values('01. Книга\01.01. Абзац\01.01.01. Строка\01.01.01.01. Слово\01.01.01.01.01. Дело\01.01.01.01.01.01 Государево');
insert #таблица values('\01.01. Абзац\\01.01.01.01. Слово');

select t.Поле,
       left(t.Поле, a.first_slash - 1) as Книга,
       substring(z.Slashed_Поле, a.first_slash  + 1, b.second_slash - a.first_slash  - 1) as Абзац,
       substring(z.Slashed_Поле, b.second_slash + 1, c.third_slash  - b.second_slash - 1) as Строка,
       substring(z.Slashed_Поле, c.third_slash  + 1, d.fourth_slash - c.third_slash  - 1) as Слово
from #таблица t
     cross apply (select t.Поле + '\\\\' as Slashed_Поле) z
     cross apply (select charindex('\', z.Slashed_Поле) as first_slash) a
     cross apply (select charindex('\', z.Slashed_Поле, a.first_slash  + 1) as second_slash) b
     cross apply (select charindex('\', z.Slashed_Поле, b.second_slash + 1) as third_slash)  c
     cross apply (select charindex('\', z.Slashed_Поле, c.third_slash  + 1) as fourth_slash) d;
12 фев 13, 10:46    [13912397]     Ответить | Цитировать Сообщить модератору
Топик располагается на нескольких страницах: [1] 2   вперед  Ctrl      все
Все форумы / Microsoft SQL Server Ответить