可以使用分析函数来查找以其他词开头的词的子集吗?

时间:2018-09-01 05:53:13

标签: sql oracle

不是重复的:我另一个标题相同的问题针对MySQL,这个针对oracle

我试图找到一种遍历单词的有序列表的单一方法,寻找当前单词开头的最短的先前单词

基本上在以下列表中(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

尽管勇敢以勇敢和胸罩开头,但其词根是bra,因为bra短于勇敢

我感觉可以做到这一点,方法是创建一列,每当当前行单词不以任何先前的行单词开头并且当前行单词的长度不大于先前的行单词时,该列就递增,然后将其用作我坚持使用的是“带有任何前一行字”位-本质上,Apple和Application均以App开头,但Application并非以Apple开头(而Bravey确实以Brave开头),因此比较立即数像上一行一样无法显示上一行

我已经可以使用MySQL和SQLS中的联接和变量,以及在Oracle中进行联接(将表自身返回几次)来完成此操作。我想知道是否有一种有效的方法可以避免所有联接的使用

2 个答案:

答案 0 :(得分:1)

在Oracle中,您可以使用MATCH_RECOGNIZE子句轻松解决此问题。问题是MATCH_RECOGNIZE需要Oracle 12.1或更高版本。

MATCH_RECOGNIZE具有分析功能的某些功能,但添加了一些其他功能。在以下解决方案中,关键部分是能够一次性将行标记为“根”(我将其命名为r)或“扩展”(e),同时能够-在同一遍中-识别出一个“组”(在技术上是一个 match )的结束处,然后是下一个组的开始-并仍在同一遍中对每个匹配的值求和。< / p>

我不认为仅使用分析功能就可以轻松完成同样的事情。

注意:对于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
;

答案 1 :(得分:0)

您可以尝试在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中的LIKEGROUP 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)

Results

|  NAME | SUM(AMOUNT) |
|-------|-------------|
|   BRA |          14 |
| CANED |           2 |
|   APP |          12 |
| CANES |           4 |
|   BOW |           2 |