Можно ли использовать аналитические / оконные функции для поиска подмножества слов, начинающих другие слова? - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь найти однопроходный способ обхода упорядоченного списка слов, ища самое короткое предыдущее слово, с которого начинается текущее слово

По существу в следующем списке:

'APP',3
'APPLE',2
'APPLICATION',7
'BOW',2
'BRA',6
'BRAVE',5
'BRAVERY',3
'CANED',2
'CANES',4

Я бы хотел исключить APPLE, APPLICATION, BRAVE и BRAVERY, но добавить их числовые оценки к корневому слову, с которого они начинаются, поэтому APP набирает 3 + 2 + 7, а BRA - 6 + 5 + 3

'APP',12
'BRA',14
'BOW',2
'CANED',2
'CANES',4

Хотя храбрость начинается с храбрости и бюстгальтера, корень этого слова - бюстгальтер, потому что бюстгальтер короче смельчака

У меня такое ощущение, что это можно сделать, создав столбец, который увеличивается каждый раз, когда текущее слово строки не начинается с какого-либо предыдущего слова строки, а текущее слово строки не длиннее предыдущего слова строки, затем используйте его как раздел. Это бит «с любым предыдущим словом строки», на котором я застрял - по сути, Apple и приложение оба начинаются с приложения, но приложение не начинается с Apple (а храбрость начинается с храброго), поэтому сравнивает непосредственный предыдущая строка как текущая строка не работает

Я не очень беспокоюсь о том, что это за БД; Я использую аналитику MySQL 8 для этого, но это более общий метод, который я использую после того, как я могу с такой же легкостью заставить наш sqlserver или oracle выполнять работу

Я уже могу сделать это с помощью объединений, мне интересно, есть ли способ, позволяющий избежать любого использования присоединений

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Альтернативная версия с использованием cte's. Также включите создание вставки, чтобы вы могли вырезать и вставить в качестве полного примера.

declare @w table(word varchar(20), cnt int)
insert @w values ('APP',3)
,('APPLE',2)
,('APPLICATION',7)
,('BRA',6)
,('BRAVE',5)
,('BRAVERY',3)
,('BOW',2)
,('CANES',4)
,('CANED',2)

;with cte as(
    select w.word, w2.word as baseword, w.cnt
    from @w w
    join @w w2 on w.word like w2.word+'%' 
    and not exists(select * from @w w3 where w.word like w3.word+'%' and len(w3.word)<len(w2.word))
)
select baseword, sum(cnt) as [count] from cte group by baseword

Выход:

baseword    count
APP    12
BOW     2
BRA    14
CANED   2
CANES   4
0 голосов
/ 31 августа 2018

Я понимаю, что здесь не используются оконные / аналитические функции, но если список упорядочен, это довольно простая проблема, просто сохраняйте строку текущего префикса до тех пор, пока следующее слово в списке не будет соответствовать ей (т.е. Name NOT LIKE CONCAT(@prefix, '_%') и в этот момент измените префикс на это слово, чтобы вы могли создать список слов и их префиксов:

SELECT Name, Value, @prefix:=IF(Name NOT LIKE CONCAT(@prefix, '_%'), Name, @prefix) AS prefix
FROM table1
JOIN (SELECT @prefix := '~') p;

Выход:

Name            Value   prefix
APP             3       APP
APPLE           2       APP
APPLICATION     7       APP
BOW             2       BOW
BRA             6       BRA
BRAVE           5       BRA
BRAVERY         3       BRA
CANES           4       CANES
CANED           2       CANED

Эти данные затем можно суммировать и группировать по префиксу:

SELECT prefix, SUM(`Value`)
FROM (SELECT Name, Value, @prefix:=IF(Name NOT LIKE CONCAT(@prefix, '_%'), Name, @prefix) AS prefix
      FROM table1
      JOIN (SELECT @prefix := '~') p
      ) t2
GROUP BY prefix

Выход:

prefix  SUM(`Value`)
APP     12
BOW     2
BRA     14
CANED   2
CANES   4

Демонстрация SQLFiddle (Обратите внимание, я взял на себя смелость сортировки BOW до BRA)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...