SQL Server - Найти частоту встречаемости (по строке, а не по слову) наиболее распространенных слов в столбце. - PullRequest
2 голосов
/ 21 мая 2019

Этот вопрос задавался несколько раз, но я не могу найти конкретный ответ, который мне нужен. У меня есть запрос, который находит наиболее часто встречающиеся слова в столбце в SQL Server и перечисляет их по количеству их появлений. Проблема в том, что если слово появляется несколько раз подряд, оно считается один раз для каждого появления. Я хотел бы считать каждое слово только один раз в строке.

Таким образом, строка со значением «Быть ​​или не быть» будет считаться «до» и «Быть» один раз каждый, а не дважды каждый для целей общей частоты.

Вот текущий запрос, который также удаляет общие слова, такие как местоимения, и заменяет все часто встречающиеся разделители пробелами. Он немного староват, поэтому я подозреваю, что он может быть намного аккуратнее.

    SELECT   sep.Col Phrase, count(*) as Qty
    FROM (
        Select * FROM (
            Select value = Upper(RTrim(LTrim(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Title, ',', ' '), '.', ' '), '!', ' '), '+', ' '), ':', ' '), '-', ' '), ';', ' '), '(', ' '), ')', ' '), '/', ' '), '&', ''), '?', ' '), '  ', ' '), '  ', ' ')))) 
            FROM Table
        ) easyValues
        Where value <> ''
        ) actualValues 
        Cross Apply dbo.SeparateValues(value, ' ') sep
    WHERE sep.Col not in ('', 'THE', 'A', 'AN', 'WHO', 'BOOK', 'AND', 'FOR', 'ON', 'HAVE', 'YOUR', 'HOW', 'WE', 'IN', 'I', 'IT', 'BY', 'SO', 'THEIR', 'IS', 'OR', 'HE', 'OF', 'WHAT'
                        , 'HIM', 'HIS', 'SHE', 'HER', 'MY', 'FROM', 'US', 'OUR', 'AT', 'ALL', 'BE', 'OF', 'TO', 'YOU', 'WITH', 'THAT', 'THIS', 'WAS', 'ARE', 'THERE', 'BUT', 'HAS'
                        , '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'WILL', 'MORE', 'DIV', 'THAN', 'EACH', 'GET', 'ANY')
          and LEN(sep.Col) > 2
    GROUP By sep.Col
    HAVING count(*) > 1

Цените любые мысли о лучшем способе сделать это, решая проблему повторных слов.

Ответы [ 3 ]

2 голосов
/ 21 мая 2019

Вам просто нужно GROUP BY дважды.

Сначала с помощью sep.Col и Table.ID удалите дубликаты подряд. В вашей таблице есть столбец ID, верно?

Во-вторых, просто на sep.Col, чтобы получить окончательный счет.

Я также переписал ваш запрос, используя CTE, чтобы сделать его читабельным. По крайней мере, для меня это более читабельно.

WITH
easyValues
AS
(
    Select
        ID
        ,value = Upper(RTrim(LTrim(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Replace(Title, ',', ' '), '.', ' '), '!', ' '), '+', ' '), ':', ' '), '-', ' '), ';', ' '), '(', ' '), ')', ' '), '/', ' '), '&', ''), '?', ' '), '  ', ' '), '  ', ' ')))) 
    FROM Table
)
,actualValues
AS
(
    SELECT
        ID
        ,Value
    FROM easyValues
    Where value <> ''
)
,SeparateValues
AS
(
    SELECT
        ID
        ,sep.Col
    FROM
        actualValues
        Cross Apply dbo.SeparateValues(value, ' ') AS sep
    WHERE
        sep.Col not in ('', 'THE', 'A', 'AN', 'WHO', 'BOOK', 'AND', 'FOR', 'ON', 'HAVE', 'YOUR', 'HOW', 'WE', 'IN', 'I', 'IT', 'BY', 'SO', 'THEIR', 'IS', 'OR', 'HE', 'OF', 'WHAT'
                        , 'HIM', 'HIS', 'SHE', 'HER', 'MY', 'FROM', 'US', 'OUR', 'AT', 'ALL', 'BE', 'OF', 'TO', 'YOU', 'WITH', 'THAT', 'THIS', 'WAS', 'ARE', 'THERE', 'BUT', 'HAS'
                        , '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'WILL', 'MORE', 'DIV', 'THAN', 'EACH', 'GET', 'ANY')
        and LEN(sep.Col) > 2
)
,UniqueValues
AS
(
    SELECT
        ID, Col
    FROM
        SeparateValues
    GROUP BY
        ID, Col
)
SELECT
    Col AS Phrase
    ,count(*) as Qty
FROM UniqueValues
GROUP By Col
HAVING count(*) > 1
;
1 голос
/ 21 мая 2019

Насколько я могу судить, функция STRING_SPLIT вместе с CROSS APPLY может дать вам то, что вы хотите.Вы можете разделить строку на основе разделителя пробелов, выделить каждое слово по отдельности, а затем считать во внешнем запросе.Я пропустил ту часть, где вы не выбираете конкретные слова для краткости.

Fiddle <> :

CREATE TABLE phrases(phrase NVARCHAR(MAX));

INSERT INTO phrases(phrase)VALUES(N'To be or not to be'),(N'this is not a phrase'),(N'And why is this not another one');

SELECT 
    w.value,
    COUNT(*) 
FROM 
    phrases AS p 
    CROSS APPLY (
        SELECT DISTINCT 
            value 
         FROM 
            STRING_SPLIT(p.phrase,N' ')
    ) AS w
GROUP BY 
    w.value;
1 голос
/ 21 мая 2019

Чтобы выполнить ваше требование, вы можете использовать FUNCTION, чтобы разбить строку на список слов по пробелу ''.С помощью этой функции вы можете использовать динамический SQL-подобный курсор для получения окончательного значения.

Сначала создайте FUNCTION as- Источник кода: stackoverflow

CREATE  FUNCTION dbo.splitstring ( @stringToSplit VARCHAR(MAX) )
RETURNS @returnList TABLE ([Word] [nvarchar] (500))
AS
BEGIN
    DECLARE @name NVARCHAR(255)
    DECLARE @pos INT

    WHILE CHARINDEX(' ', @stringToSplit) > 0
    BEGIN
    SELECT @pos  = CHARINDEX(' ', @stringToSplit)  
    SELECT @name = SUBSTRING(@stringToSplit, 1, @pos-1)

    INSERT INTO @returnList 
    SELECT @name

    SELECT @stringToSplit = SUBSTRING(@stringToSplit, @pos+1, LEN(@stringToSplit)-@pos)
END

INSERT INTO @returnList
SELECT @stringToSplit

RETURN
END

Затем используйтеэтот скрипт CURSOR для получения окончательного результата -

DECLARE @Value VARCHAR(MAX)
DECLARE @WordList TABLE
(
  Word VARCHAR(200)
)

DECLARE db_cursor CURSOR 
FOR 
SELECT Upper(RTrim(LTrim(Replace(Replace(Replace(Replace(Replace
                        (Replace(Replace(Replace(Replace(Replace(Replace(Replace
                        (Replace(Replace(title, ',', ' '), '.', ' '), '!', ' '), '+', ' '), ':', ' '), '-', ' '), ';', ' ')
                        , '(', ' '), ')', ' '), '/', ' '), '&', ''), '?', ' '), '  ', ' '), '  ', ' ')))) [Value]
FROM table

OPEN db_cursor  
FETCH NEXT FROM db_cursor INTO @Value  

WHILE @@FETCH_STATUS = 0  
BEGIN  

    INSERT INTO @WordList
    SELECT DISTINCT Word FROM [dbo].[splitstring](@Value)
    WHERE Word NOT IN ('', 'THE', 'A', 'AN', 'WHO', 'BOOK', 'AND', 'FOR', 'ON', 'HAVE', 'YOUR', 'HOW', 'WE', 'IN', 'I', 'IT', 'BY', 'SO', 'THEIR', 'IS', 'OR', 'HE', 'OF', 'WHAT'
                    , 'HIM', 'HIS', 'SHE', 'HER', 'MY', 'FROM', 'US', 'OUR', 'AT', 'ALL', 'BE', 'OF', 'TO', 'YOU', 'WITH', 'THAT', 'THIS', 'WAS', 'ARE', 'THERE', 'BUT', 'HAS'
                    , '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'WILL', 'MORE', 'DIV', 'THAN', 'EACH', 'GET', 'ANY')
    AND LEN(Word) > 2

    FETCH NEXT FROM db_cursor INTO @Value 
END 

CLOSE db_cursor  
DEALLOCATE db_cursor


SELECT Word,COUNT(*)
FROM @WordList
GROUP BY Word 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...