2016-11-22 60 views
1

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

什么我在寻找一个例子:

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

感谢您的帮助!

回答

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; 
+0

@ user961743它是你需要什么,或者你想只计算连续的相同字符? – Kacper

+0

这似乎是我需要的。它确实使我的查询执行时间增加了,但它适用于迄今为止所尝试的内容! –

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 .... 
1

这是一种方法。要计算一个字符出现的次数(例如'x'),存在于像'zxxydds'这样的字符串中,最快的方法是使用字符串函数REPLACE()从字符串中删除所有出现的'x'(将'x'替换为''),然后从原始字符串的长度中减去结果字符串的长度。必须小心谨慎,因为如果字符串全部为'x'(如'xxxxx'),则结果字符串为空,Oracle中空字符串的长度为NULL而不是零。因此,我们需要使用coalesce()的呼叫来使此长度为零而不是NULL

其余的是简单的:在一个许可证号创建的所有可能字符的“假表”(例如,0-9A-F,但可以推广到任何字符名单) - 我做一个简单的table()函数 - 然后进行交叉连接,计算每个字符的出现次数,然后按license_number进行max()分组。我做了一个最后的简化:如果C是一个常量(一个固定的数字),并且x的范围超过一组,然后max(C-x) = C - min(x)

with 
    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 
    ) 
-- end of test data; solution (SQL query) begins below this line 
select t.license_number, 
     length(t.license_number) - 
     min(coalesce(length(replace(t.license_number, c.column_value, '')), 0)) 
                 as max_count 
from test_data t cross join 
     table(sys.odcivarchar2list(
       '0','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F')) c 
group by t.license_number 
; 

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

下面是对同一问题的不同公式的解决方案。假设我们想在许可证号码中找到相同字符的最大数量的连续出现次数。例如,如果许可证号是112211220,则1和2都出现4次。但是,同一字符的最大连续出现次数为2.

此问题需要将每个许可证号码拆分为其各个字符,并跟踪它们在字符串中的位置。我在第一次CTE中这样做(“第一次”不包括测试数据,就是这样)。然后,通过使用所谓的Tabibitosan方法(CTE使用两个不同的电话号码row_number()),通常可以最有效地识别连续的“某物”。之后,这是一个简单的分组,计数和取最大值的问题。

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