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

Не дубликат: другой мой вопрос с таким же названием нацелен на MySQL, этот нацелен на оракула

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

По существу в следующем списке (2 столбца, varchar, int):

'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 и SQLS, а также соединения (присоединение таблицы обратно к себе несколько раз) в Oracle. Мне интересно, есть ли один хитовый способ, который избегает любого использования объединения

Ответы [ 2 ]

0 голосов
/ 02 сентября 2018

В Oracle вы можете легко решить эту проблему с помощью предложения MATCH_RECOGNIZE. Уловка в том, что MATCH_RECOGNIZE требует Oracle версии 12.1 или выше.

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

Я не думаю, что вы можете сделать то же самое легко с помощью аналитических функций.

ПРИМЕЧАНИЕ : для более старых версий Oracle проблему можно решить с помощью предложения MODEL (также принадлежащего Oracle). Для этого требуется Oracle 10.1 или выше. Решение, представленное внизу этого ОТВЕТА (после решения MATCH_RECOGNIZE).

with
  simulated_data(word, val) as (
    select 'APP'        , 3 from dual union all
    select 'APPLE'      , 2 from dual union all
    select 'APPLICATION', 7 from dual union all
    select 'BOW'        , 2 from dual union all
    select 'BRA'        , 6 from dual union all
    select 'BRAVE'      , 5 from dual union all
    select 'BRAVERY'    , 3 from dual union all
    select 'CANED'      , 2 from dual union all
    select 'CANES'      , 4 from dual
  )
select root_word, total_value
from   simulated_data
match_recognize(
  order by word
  measures r.word   as root_word,
           sum(val) as total_value
  pattern  ( r e* )
  define   e as e.word like r.word || '%'
)
;

ROOT_WORD   TOTAL_VALUE
----------- -----------
APP                  12
BOW                   2
BRA                  14
CANED                 2
CANES                 4

Решение с использованием предложения MODEL:

with
  simulated_data(word, val) as (
    select 'APP'        , 3 from dual union all
    select 'APPLE'      , 2 from dual union all
    select 'APPLICATION', 7 from dual union all
    select 'BOW'        , 2 from dual union all
    select 'BRA'        , 6 from dual union all
    select 'BRAVE'      , 5 from dual union all
    select 'BRAVERY'    , 3 from dual union all
    select 'CANED'      , 2 from dual union all
    select 'CANES'      , 4 from dual
  )
select rw as root_word, tv as total_value
from   (
         select rw, tv, fl
         from   simulated_data
         model
           dimension by (row_number() over (order by word) as rn)
           measures     (word, val, rpad('x', 4000, 'x') as rw, 0 as tv, 0 as fl)
           rules        (
             rw[any] = case instr(word[cv()], rw[cv()-1]) 
                            when 1 then rw[cv()-1] else word[cv()] end,
             tv[any] = case rw[cv()] when rw[cv()-1] 
                            then tv[cv()-1] + val[cv()] else val[cv()] end,
             fl[any] = case rw[cv()] when rw[cv()+1] 
                            then 0 else 1 end
           )
       )
where  fl = 1
;
0 голосов
/ 01 сентября 2018

Вы можете попробовать написать CASE WEHN с LIKE в GROUP BY

Запрос 1 :

SELECT 
(CASE
    WHEN name LIKE 'APP%' THEN 'APP'
    WHEN name LIKE 'BRA%' THEN 'BRA'
    ELSE name
END) name,SUM(amount) 
FROM T
GROUP BY 
CASE
    WHEN name LIKE 'APP%' THEN 'APP'
    WHEN name LIKE 'BRA%' THEN 'BRA'
    ELSE name
END

Если вы не хотите использовать CASE WEHN с LIKE в GROUP BY.

Я бы создал таблицу mapper для вашего ключевого слова, потому что вам нужно сообщить программе, какое ключевое слово вы ожидаете.

CREATE TABLE T(name varchar(50),amount int);

insert into t values ('APP',3);
insert into t values ('APPLE',2);
insert into t values ('APPLICATION',7);
insert into t values ('BOW',2);
insert into t values ('BRA',6);
insert into t values ('BRAVE',5);
insert into t values ('BRAVERY',3);
insert into t values ('CANED',2);
insert into t values ('CANES',4);

CREATE TABLE maaper(
    name VARCHAR(50)
);

INSERT INTO maaper VALUES ('APP');
INSERT INTO maaper VALUES ('BRA');

Запрос 1 :

SELECT coalesce(t2.name,t1.name) name,sum(AMOUNT)
FROM T t1 LEFT JOIN (
    SELECT name 
    FROM maaper
) t2 ON t1.name like  t2.name || '%'
group by coalesce(t2.name,t1.name)

Результаты :

|  NAME | SUM(AMOUNT) |
|-------|-------------|
|   BRA |          14 |
| CANED |           2 |
|   APP |          12 |
| CANES |           4 |
|   BOW |           2 |
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...