Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: Разбить строку на слова

Всем привет!

Есть массив строк, допустим 350. Каждая содержит около 100 слов.
Необходимо разить все строки на слова, и затем подсчитать как часто каждое слово повторяется.

Есть хорошая функция regexp_substr+connect by которая жУтко тормозить.
К примеру вот этот код вы уже сможете выполнить

create table t1
as
with t1 as
 (select '####<Mar 20, 2014 2:57:37 AM MSK> <Info> <Health> <vs-c06-as06-1182> <IBR_server1> <weblogic.GCMonitor> <<anonymous>> <> <> <1395269857320> <BEA-310002> <65% of the total memory in the server is free> ' as c1
    from dual
  connect by level <= 2)
SELECT to_char(trim(regexp_substr(c1, '[^ ]+', 1, LEVEL))) as c2
  FROM t1
CONNECT BY LEVEL <= regexp_count(c1, ' ') + 1


Есть ли какой ни будь другой способ разбить строку на подстроки?

Мне приходит в ум только заложиться на 1000 тыщ слов максимум в строке, и использовать instr или тот же regexp
Ответ:
Добрый Э - Эх
Skulll,

а вообще, после многократных обсуждений тут на форуме все пришли к выводу, что "размножать " строки нужно как минимум через коррелированный мультисет-подзапрос:
with t1 as
 (select level as lv, '####<Mar 20, 2014 2:57:37 AM MSK> <Info> <Health> <vs-c06-as06-1182> <IBR_server1> <weblogic.GCMonitor> <<anonymous>> <> <> <1395269857320> <BEA-310002> <65% of the total memory in the server is free> ' as c1
    from dual
 connect by level <=  100)

SELECT to_char(trim(regexp_substr(c1, '[^ ]+', 1, p.column_value))) as c2
  FROM t1
     , table(cast(multiset(select rownum
                             from dual
                          connect by level <= regexp_count(c1, ' ') + 1) as sys.odcinumberlist)
             ) p

(а если версия позволяет, то и вообще через APPLY)

Данный скрипт у меня почему-то разбивает только первую строку в таблице, а дальше идет тупо null. Почему?
Вопрос: Разбить строку

Приветствую!

Помогите, пожалуйста, решить следующую задачу...
Есть набор записей, в которых есть строки (длинные):
ID1, строка1
ID2, строка2
ID3, строка3

Необходимо разбить строки внутри записей так, чтобы получился рекордсет следующего вида:
ID1, номер строки, часть строки1
ID1, номер строки, часть строки1
ID1, номер строки, часть строки1
ID2, номер строки, часть строки2
ID2, номер строки, часть строки2
ID3, номер строки, часть строки3

И т.д... С одной строкой я решение нашел (через regexp_substr). Но что-то недопонимаю, как его прикрутить внутрь запроса...
Ответ:
env
Nikolay_Ch,

with t as (select 1 m,'строканачасти' l from dual union all
           select 2, 'другаястроканачасти' from dual)
select substr(l,(level-1)*:k,:k),'строка '||m,'часть '||level
from t
connect by level<=(length(l)/:k)+1 and prior m = m and prior dbms_random.value>0;


select substr(l,(level-1)*:k+1,:k),'строка '||m,'часть '||level
Вопрос: Применение функции substring для подстрок переменной длины в Transact-SQL

Добрый день! Помогите, пожалуйста, разобраться с синтаксисом функции substring для подстрок переменной длины в Transact-SQL.
Исходные данные.
Поле таблицы «Message» содержит данные в следующем виде:

Message
Номер клиента 147235689. ФИО клиента Иванов Иван Петрович, паспорт 21 00 827965
Номер клиента 147328592. ФИО клиента Семёнов Сергей Иннокентьевич, паспорт 21 96 127994
Номер клиента 149528964. ФИО клиента Разумова Ирина Геннадьевна, паспорт 24 65 792971
Номер клиента 148522547. ФИО клиента Огнева Анастасия Юрьевна, паспорт 23 12 954728

Необходимо в отдельные столбцы извлечь номер клиента, ФИО клиента и паспортные данные, чтобы конечные данные имели следующий вид:
NumberFullnameDocument
147235689Иванов Иван Петрович21 00 827965
147328592Семёнов Сергей Иннокентьевич21 96 127994
149528964Разумова Ирина Геннадьевна24 65 792971
148522547Огнева Анастасия Юрьевна23 12 954728

В случае с номером клиента и паспортными данными текстовые переменные имеют фиксированную длину (9 и 12 символов соответственно, и функция substring дает нужный результат.
SQL
1
2
SUBSTRING(Message, charindex(‘Номер клиента’, Message, 1) + 14, 9)
SUBSTRING(Message, charindex(‘паспорт’, Message, 1) + 8, 12)
Но в случае с ФИО клиента длина подстроки переменная. Пробовала указывать вычисляемую длину подстроки в функции substring:

SQL
1
SUBSTRING(Message, charindex((‘ФИО клиента’, Message, 1) + 12, charindex(‘паспорт’, Message, 1) - charindex(‘ФИО клиента’, Message, 1) - 14)
и в этом случае возникает ошибка “Invalid length parameter passed to the LEFT or SUBSTRING function.”
При этом отдельно функция charindex возвращает номера искомых позиций в строке.

Как избежать возникновения ошибки и получить с помощью функции substring ФИО в отдельном столбце?
P.S. Данные вымышлены.
Ответ: pollynom, проверить на 2008 возможности нет. Синтаксически запрос верный и работает на 2008 R2 и выше.

Попробуйте переписать через CTE:
T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
with t1 as
(
 select
  t.id, t.msg, a.x
 from
  @t t cross apply
  (select x as[*] from #t where id = t.id for xml path(''), type) a(x)
),
t2 as
(
 select
  id, msg, cast(x.value('.', 'varchar(max)') as xml) as x
 from
  t1
)
select
 t2.id, t2.msg,
 c.n.value('cl[1]', 'varchar(100)'),
 c.n.value('fio[1]', 'varchar(100)'),
 c.n.value('doc[1]', 'varchar(100)')
from
 t2 cross apply
 x.nodes('/') c(n);
Так же желательно выяснить версию своего сервера - и, если понадобится, накатить последний SP.
Вопрос: Вырезать только цифры определенной длины из текста

Здравствуйте , помогите вырезать цифры определенной длины из текста т.е. у меня стоит задача вытащить ИИН из текста
вот пример (12 символ ИИН)

Перечисление от клиента Трамп Доналд Нашевич ИИН/БИН клиента: 650818400914 на сумму: 25930,Код платежа 182470, 


650818400914
Ответ: orawish,

Спасибо, то что надо
Вопрос: Разбить строку по символу в запросе

Привет!
Как можно разбить строку по символу в запросе?

Например есть строка 45/89, нужно получить два поля с значениями 45/89. Значения могут быть разными, например: 56/700, 5/100, 2/3 и т.д.
Ответ: wadman, точно. Спасибо всем!
Вопрос: Вывод строк с определенными id в первую очередь

Здравствуйте! Возможно ли одним запросом вывести все строки удовлетворяющие условиям так, чтобы первыми шли строки с определенными id, а затем все остальные?
Ответ: ORDER BY FIELD (id, 2, 10, 3, 88, 23)
Вопрос: Разбить строку на слова PL SQL

Написать хранимую процедуру, которая принимает 1)- параметр – строку текста , состоящую из слов, а возвращает 2 параметра: 1)слово, имеющее максимальную длину и 2) количество символов в этом слове.
Ответ:
Сообщение от Grossmeister
В цикле отрезаешь по одному слову с пом. INSTR + SUBSTR
Ну ладно, раз уже появилась вторая абсолютно аналогичная тема, сделаем вас процедуру без регулярных выражений. Но тут удобнее немного в другом порядке. Самое первое действие - замена пробельных символов на пробелы. Это будет
SQL
1
v_txt := translate(v_txt, chr(8)||chr(9)||chr(10)||chr(13), ' '||' '||' '||' ');
Если какой-то пробельный символ забыл - легко добавить. Главное - понятно как. Специально пробелы через конкатенацию написал.
Вторым шагом неодиночные пробелы заменяем на одиночные. Это можно сделать так:
SQL
1
2
3
4
while instr(v_txt, ' '||' ') >0
loop
    v_txt := REPLACE(v_txt, ' '||' ', ' ');
END loop;
Третьим шагом обрезаем пробелы в начале и в конце. Ну это совсем просто
SQL
1
v_txt := TRIM(v_txt);
Теперь приступаем к поиску максимальной подстроки.
SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
IF instr(v_txt, ' ') =0 THEN
    p_ret := v_txt;
    p_len := LENGTH(v_txt);
ELSE
    p_ret := '';
    p_len := 0;
END IF;
while  instr(v_txt, ' ')>0
loop
    pos := instr(v_txt, ' ');
    v_ret := substr(v_txt, pos-1, pos-1);
    v_len := LENGTH(v_ret);
    IF v_len > p_len THEN
        p_ret :=v_ret;
    END IF;
    v_txt := substr(v_txt, pos+1);
END loop; 
Сейчас отлажу процедуру и помещу в следующем посте

Добавлено через 36 минут
В ранее приведенных кусках кода была парочка мелких ошибок и пропусков, которые вылезли при отладке. Процедура получилась такая
Кликните здесь для просмотра всего текста
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
CREATE OR REPLACE
PROCEDURE maxword(p_txt    IN  varchar2,  
                        p_ret    OUT varchar2, 
                        p_len    OUT NUMBER) 
IS
    v_txt   varchar2(4000);
    v_len   NUMBER;
    pos     NUMBER;
    v_ret   varchar2(4000);
BEGIN
    v_txt := translate(p_txt, chr(8)||chr(9)||chr(10)||chr(13), ' '||' '||' '||' ');    --  все (неодиночные) пробельные символы заменяются пробелом
    while instr(v_txt, ' '||' ') >0
    loop
        v_txt := REPLACE(v_txt, ' '||' ', ' ');
    END loop;                                           --  парные пробелы заменяются на одиночные
    v_txt := TRIM(v_txt);                               --  убираются пробелы в начале и конце строки
    
    IF instr(v_txt, ' ') =0 THEN
        p_ret := v_txt;
        p_len := LENGTH(v_txt);
    ELSE
        p_ret := '';
        p_len := 0;
    END IF;                             -- присваиваются начальные значения
    while  instr(v_txt, ' ')>0
    loop
        pos := instr(v_txt, ' ');
        v_ret := substr(v_txt, 1, pos-1);
        v_len := LENGTH(v_ret);
        IF v_len > p_len THEN
            p_ret := v_ret;
            p_len := v_len;
        END IF;
        v_txt := substr(v_txt, pos+1, LENGTH(v_txt));
    END loop;                           -- ищется первое слово максимальной длины
END;

Ничего так получилось. Даже не очень длинно. Пример вызова процедуры я уже приводил выше
Вопрос: Разбить строку на слова с условием длины слова

Добрый день.

Есть ли способ средствами языка mysql разбить результат SELECT str FROM table where id=1 на отдельные слова с условием длины слова (не учитывать слова короче 4-х символов)?
str - строка из трех-восьми слов разделенных пробелом.

Спасибо.
Ответ: Для выделения слова номер N можно использовать двукратный SUBCRTING_INDEX(). Именно для этого - подачи N - и требуется опорная таблица. Останется отсеять слова короче 4 символов, что тоже не самая сложная задача.
А почему бы не нормализовать исходные данные?
Вопрос: Разбить строку на подстроки в WITH

Возникли проблемы в СРМ с созданием отчёта (SSRS) при передачи multivalue параметров в хранимку. Если писать этот запрос в редакторе отчётов, всё работает, но когда я импортирую в хранимку - начинаются проблемы: SQL не распознаёт multivalue параметры.
код следующий:

T-SQL
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SELECT        stage.new_name AS stage_name, ISNULL(mission.new_gradename,'Задача без исполнителя') AS mission_grade,  ISNULL(mission.new_systemuseridname,'Задача без исполнителя') AS own_user_name, mission.new_name AS mission_name, mission.new_time AS mission_plan, 
                         SUM(billing.new_billed_time) AS mission_fact, mission.new_time - SUM(billing.new_billed_time) AS mission_remainder, billing_without_missions_set.billing_without_missions_time AS billing_without_mission, 
                         plan_by_grade.plan_by_grade_collumn AS plan_by_grade, fact_by_grade.fact_by_grade_collumn AS fact_by_grade, 
                         plan_by_grade.plan_by_grade_collumn - fact_by_grade.fact_by_grade_collumn AS remainder_by_grade
FROM            Filterednew_stage AS stage LEFT OUTER JOIN
                         Filterednew_mission AS mission ON stage.new_stageid = mission.new_stageid LEFT OUTER JOIN
                         Filterednew_billing AS billing ON stage.new_stageid = billing.new_stageid AND billing.new_missionid = mission.new_missionid LEFT OUTER JOIN
                             (SELECT        SUM(new_billed_time) AS billing_without_missions_time, new_stageid AS billing_without_missions_stage, new_systemuserid AS billing_without_missions_user
                               FROM            Filterednew_billing
                               WHERE        (new_missionid IS NULL)
                               GROUP BY new_stageid, new_systemuserid) AS billing_without_missions_set ON stage.new_stageid = billing_without_missions_set.billing_without_missions_stage AND 
                         mission.new_systemuserid = billing_without_missions_set.billing_without_missions_user LEFT OUTER JOIN
                             (SELECT        SUM(new_time) AS plan_by_grade_collumn, new_stageid AS plan_stage, new_grade AS plan_grade
                               FROM            Filterednew_mission AS mission
                               GROUP BY new_stageid, new_grade) AS plan_by_grade ON stage.new_stageid = plan_by_grade.plan_stage AND mission.new_grade = plan_by_grade.plan_grade LEFT OUTER JOIN
                             (SELECT        SUM(new_billed_time) AS fact_by_grade_collumn, new_stageid, new_grade
                               FROM            Filterednew_billing AS billing
                               GROUP BY new_stageid, new_grade) AS fact_by_grade ON stage.new_stageid = fact_by_grade.new_stageid AND mission.new_grade = fact_by_grade.new_grade
WHERE        (stage.new_stageid IN (@Stage,','))
GROUP BY stage.new_name, mission.new_gradename, mission.new_systemuseridname, mission.new_name, mission.new_time, billing_without_missions_set.billing_without_missions_time, 
                         plan_by_grade.plan_by_grade_collumn, fact_by_grade.fact_by_grade_collumn
ORDER BY stage_name, mission_grade, own_user_name
Параметр @Stage содержит список id, разделённых запятой. Мне надо каким-то образом разделить его. Думаю, что простейший способ - разбить через WITH

T-SQL
1
2
3
4
WITH id_list(stage_id) AS
(
   SELECT ...
)
И затем в запросе просто написать
T-SQL
1
stage.new_stageid IN (SELECT stage_id FROM id_list)
Кто-нибудь может подсказать, как сделать сплит в WITH?
Ответ:
Сообщение от Якобинец
В Гугле.
Ааа! В гугле! Как же я сразу не догадался!
Ну, не хотите говорить, - не говорите.
Собственно говоря, оно мне разве надо?!
Вопрос: Разбить строку на записи через CTE

declare @d varchar(max)='11111,22,333,'

;with v(i, period) as (
	select CHARINDEX(',',@d), SUBSTRING(@d, 0, CHARINDEX(',',@d)) 
	union all
	select CHARINDEX(',', @d, i+1),SUBSTRING(@d, i+1, CHARINDEX(',',@d)-1) 
	from v 
	where i>0
)
select * from v where i>0
Если через запятую перечислены строки одинаковой длины, то все в порядке, а если разной, то получается ерунда.
Не могу понять, где я налажал.
Ответ: Antonariy, вариант с CTE
;
declare @delim  char(1)
select @delim = ';'
declare @tbl table (id int, value varchar(max))
insert into @tbl values (1, '11111;22;333;')
insert into @tbl values (2, '345;567;5643;')
;
with tdelim   as 
( select 
    t.id
   ,v.number 
from master.dbo.spt_values v 
 , @tbl t
where  substring( t.value , v.number ,1) = @delim
and v.type='P' 
and v.number <= len(t.value) and v.number > 0 
--- + учитываем начало 
union select id, 0 from  @tbl  
),
  tdelim1   as 
( select 
    d.id
   ,d.number  as start
   ,min( d1.number  ) as finish
from tdelim  d
inner join tdelim  d1
  on d1.id =d.id
  and d.number < d1.number
group by     d.id  ,d.number   
 )
select d.id
 ,d.start 
 , d.finish 
 ,substring( t.value , d.start+1  ,  d.finish -  d.start -1  ) as word
from tdelim1 d
  inner join @tbl t
    on t.id =d.id
order by d.id