Если вы используете MySQL 8.0, я бы порекомендовал для этого рекурсивное общее табличное выражение. Идея состоит в том, чтобы итеративно проходить каждое сообщение, по ходу разбивая его на слова. Все, что остается сделать, - это агрегировать.
with recursive cte as (
select
substring(concat(sent, ' '), 1, locate(' ', sent)) word,
substring(concat(sent, ' '), locate(' ', sent) + 1) sent
from messages
union all
select
substring(sent, 1, locate(' ', sent)) word,
substring(sent, locate(' ', sent) + 1) sent
from cte
where locate(' ', sent) > 0
)
select row_number() over(order by count(*) desc, word) wid, word, count(*) freq
from cte
group by word
order by wid
В более ранних версиях вы могли эмулировать такое же поведение с помощью таблицы чисел.
Демо в БД Fiddle
Примеры данных:
sent | verif
:------------------------- | ----:
hello my name is alex | <em>null</em>
hey alin and alex I'm tom | <em>null</em>
hello alex my name is alin | <em>null</em>
Результаты:
wid | word | freq
--: | :----- | ---:
1 | alex | 3
2 | alin | 2
3 | hello | 2
4 | is | 2
5 | my | 2
6 | name | 2
7 | and | 1
8 | hey | 1
9 | I'm | 1
10 | tom | 1
Когда дело доходит до сохранения результатов запроса в отдельной таблице , это, вероятно, сложнее, чем вы думаете: вам нужно иметь возможность вставлять, удалять или обновлять целевую таблицу в зависимости от изменений в исходной таблице, что невозможно сделать с помощью одного оператора в MySQL. Кроме того, поддержание актуальности флага в исходной таблице создает состояние гонки, при котором могут происходить изменения, пока вы обновляете целевую целевую таблицу.
Более простым вариантом было бы поместить запрос в представление, поэтому вы всегда будете в курсе своих данных. Для этого вы можете просто заключить приведенный выше запрос в оператор create view
, например:
create view words_view as < above query >;
Если производительность становится проблемой, вы также можете периодически обрезать и пополнять таблицу слов.
truncate table words;
insert into words < above query >;