Oracle SQL列中的最大计数重复字符数

时间:2016-11-22 14:56:45

标签: sql regex oracle oracle11g

我在许可证号码数据库中有一列。我试图确定这些数字是否合法。其中一项测试是确定是否有多次出现相同的字符。我试图确定最重复的角色的数量是多少。第二个测试是确定所有数字是否是连续的,但我将其作为一个不同的问题发布。

我正在寻找的一个例子:

LICENSE_NUMBER  MAX_COUNT
111246544       3
999999999       9
123456789       0
AAAAAAAAA       9
A12345667       2

感谢您的帮助!

4 个答案:

答案 0 :(得分:1)

这不是最漂亮的代码,如果许可证可以包含更多字符(我猜它是十六进制的),它将是长查询但你可以尝试:

select licence_number, greatest(REGEXP_COUNT(licence_number, '1'), 
  REGEXP_COUNT(licence_number, '2'), REGEXP_COUNT(licence_number, '3'), 
  REGEXP_COUNT(licence_number, '4'), REGEXP_COUNT(licence_number, '5'), 
  REGEXP_COUNT(licence_number, '6'), REGEXP_COUNT(licence_number, '7'), 
  REGEXP_COUNT(licence_number, '8'), REGEXP_COUNT(licence_number, '9'), 
  REGEXP_COUNT(licence_number, '0'), REGEXP_COUNT(licence_number, 'A'),
  REGEXP_COUNT(licence_number, 'B'), REGEXP_COUNT(licence_number, 'C'),
  REGEXP_COUNT(licence_number, 'D'), REGEXP_COUNT(licence_number, 'E'),
  REGEXP_COUNT(licence_number, 'F') ) as max_count
from table;

答案 1 :(得分:1)

这是一种方法。要计算像'x'这样的字符串中出现的字符数,例如'zxxydds',最快的方法是使用字符串函数REPLACE()删除所有出现的{{1}从字符串(通过用'x'替换'x'),然后从原始字符串的长度中减去结果字符串的长度。必须要小心,因为如果字符串全部为''(如'x'),那么结果字符串为空,Oracle中空字符串的长度为'xxxxx'而不是零。因此,我们需要调用NULL来调整此长度为零,而不是coalesce()

其余的很简单:创建许可证编号中所有可能字符的“假表”(例如,NULL0-9,但您可以推广到任何字符列表) - 我使用简单的A-F函数执行此操作 - 然后执行交叉连接,计算每个字符的出现次数,并按table()进行max()分组。我做了一个最后的简化:如果license_number是一个常数(固定数字)和C范围,那么x

max(C-x) = C - min(x)

答案 2 :(得分:1)

这是针对同一问题的不同表述的解决方案。假设我们想要在许可证号中找到相同字符的最大CONSECUTIVE事件数。例如,如果许可证号码是112211220,则1和2都会出现4次。但是,相同字符的最大CONSECUTIVE出现次数为2。

这个问题需要将每个许可证号码分解为各自的字符,并跟踪它们在字符串中的位置。我在第一次CTE中做到了这一点("第一次"不计算测试数据,即)。然后识别连续的"东西"通常使用所谓的Tabibitosan方法(使用对row_number()的两个不同调用的CTE)最有效地完成。在那之后,这是一个简单的分组,计数和最大化的问题。

with
-- begin of test data, not part of the solution
     test_data ( license_number ) as (
       select '111246544' from dual union all
       select '999999999' from dual union all
       select '123456789' from dual union all
       select 'AAAAAAAAA' from dual union all
       select 'A12345667' from dual union all
       select '112211220' from dual
     ),
-- end of test data; solution (SQL query) continues below this line
     tokenized ( license_number, idx, ch ) as (
       select license_number, level, substr(license_number, level, 1)
       from   test_data
       connect by level <= length(license_number)
           and prior license_number = license_number
           and prior sys_guid() is not null
     ),
     prep ( license_number, idx, ch, grp ) as (
       select license_number, idx, ch,
              row_number() over (partition by license_number order by idx) -
                row_number() over (partition by license_number, ch order by idx)
       from   tokenized
     ),
     grouped ( license_number, ch, grp, ct ) as (
       select   license_number, ch, grp, count(*)
       from     prep
       group by license_number, ch, grp
     )
select   license_number, max(ct) as max_count
from     grouped
group by license_number
;

<强>输出

LICENSE_NUMBER  MAX_COUNT
--------------  ---------
AAAAAAAAA               9
123456789               1
A12345667               2
999999999               9
111246544               3
112211220               2

答案 3 :(得分:0)

假设在这种情况下:123456789重复次数最多的字符的计数是1 - 而不是0,那么子查询很少的查询就可以完成工作:

SELECT LICENSE_NUMBER, max( cnt )
FROM (
    SELECT LICENSE_NUMBER, substr( LICENSE_NUMBER, x, 1 ) qq, count(*) As cnt
    FROM (
        SELECT *
        FROM table
        CROSS JOIN (
           SELECT level x FROM dual
           -- get a max length of lincence with the belo subquery
           CONNECT BY LEVEL <= ( SELECT MAX( length( LICENSE_NUMBER )) FROM table )
        )
    )
    GROUP BY LICENSE_NUMBER, substr( LICENSE_NUMBER, x, 1 )
)
WHERE qq IS NOT NULL
GROUP BY LICENSE_NUMBER
ORDER BY 1;

如果您希望打印0而不是1,只需更改第一行:

SELECT LICENSE_NUMBER, CASE max( cnt ) WHEN 1 THEN 0 ELSE max( cnt ) END 
FROM ....