2016-11-22 4 views
1

これは前回の質問の2番目の部分です。私はライセンス番号の表を持っており、合法であるかどうかを判断しようとしています。実行しようとしているテストの1つは、数値がシーケンシャル/カウントパターンの場合です。本当に役立つのは、連続する文字の最大数を得ることができる場合ですが、それはより難しいと感じています。例:Oracle SQLで番号が逐次であるかどうかを判断する方法

LICENSE_NUMBER IS_COUNTING NUM_SEQ_CHARS 
123456789  TRUE   9 
123455678  FALSE   5 
456789012  TRUE   9 
12345   TRUE   5 
123451234  FALSE   5 

ありがとうございます!

+0

あなたは「順次文字数」および実施例はその点では有用ではありません説明しませんでした。具体的には:文字列の先頭または文字列のどこに何桁の数字が連続しているかを知りたいですか? 3621234の連続する文字の数は何ですか?それは1か4か? – mathguy

答えて

0
^(01(2345678901)*(2(3(4(5(6(7(8(90?)?)?)?)?)?)?)?)? 
|12(3456789012)*(3(4(5(6(7(8(9(01?)?)?)?)?)?)?)?)? 
|23(4567890123)*(4(5(6(7(8(9(0(12?)?)?)?)?)?)?)?)? 
|34(56789)*(5(6(7(8(9(0(1(23?)?)?)?)?)?)?)?)? 
|45(6789)*(6(7(8(9(0(1(2(34?)?)?)?)?)?)?)?)? 
|56(789)*(7(8(9(0(1(2(3(45?)?)?)?)?)?)?)?)? 
|67(89)*(8(9(0(1(2(3(4(56?)?)?)?)?)?)?)?)? 
|78(9)*(9(0(1(2(3(4(5(67?)?)?)?)?)?)?)?)? 
|89()*(0(1(2(3(4(5(6(78?)?)?)?)?)?)?)?)? 
|90(1234567890)*(1(2(3(4(5(6(7(89?)?)?)?)?)?)?)?)?)$ 

2桁以上の任意の文字列に一致します。これは、完全に連続した数字で構成されます。

123456789  MATCH 
123455678  NOT MATCH 
456789012  MATCH 
12345   MATCH 

デモ:http://regexr.com/3enkb

0

このクエリは、また、シーケンシャル文字の数を計算します。ここでは

SELECT LICENSE_NUMBER, 
     CASE length(LICENSE_NUMBER) WHEN max(cnt) THEN 'TRUE' ELSE 'FALSE' END As IS_COUNTING , 
     max(cnt) As NUM_SEQ_CHARS 
FROM (
     SELECT LICENSE_NUMBER, p, count(*) As cnt 
     FROM (
      SELECT LICENSE_NUMBER, 
        SUM(xx) OVER (Partition By LICENSE_NUMBER ORDER BY x) As p 
      FROM (
        SELECT LICENSE_NUMBER, 
         x, qq, 
         CASE WHEN qq - 1 = LAG(qq) OVER (Partition By LICENSE_NUMBER ORDER BY x) 
           THEN 0 
           WHEN qq = 0 AND 9 = LAG(qq) OVER (Partition By LICENSE_NUMBER ORDER BY x) 
           THEN 0 
           ELSE 1 
          END As xx 
        FROM (
         SELECT LICENSE_NUMBER, x, substr(LICENSE_NUMBER, x, 1) qq 
         FROM (
          SELECT * 
          FROM table 
          CROSS JOIN (
          SELECT level x FROM dual 
          CONNECT BY LEVEL <= (SELECT MAX(length(LICENSE_NUMBER)) FROM table) 
         ) 
        ) 
       ) 
      ) 
     ) 
     GROUP BY LICENSE_NUMBER, p 
) 
GROUP BY LICENSE_NUMBER 
1

は、与えられたライセンス数の連続した増加の最大桁数を決定するための効率的な方法であります。私はYES/NO列を気にしませんでした。例えば、MAX_COUNTlength(license_number)を比較するなど、簡単に得られます。それを運動として残す。

ライセンス番号を個々の文字に分割し、位置を追跡する必要があります。オラクルはmod(-1, 10)が-1であり、9ではないと信じているので(MODULO関数を再学習するためには、実際に小学校に戻る必要があります)、10を加算する必要がありますすべてのケースで正しい結果が得られます(以下のソリューションでは「奇妙」を説明します)。今問題は次のようになります。各ライセンス番号に対して、最長の "等価"残基mod 10を探します。

"Tabibitosanメソッド"(CTEのrow_number()の2つの違い、私の解決策ではprepと呼ばれています)を使用して、シーケンス内の連続した「何か」を見つけることが最も効率的です。それで、それはすべてグループ化、数えられ、max()を取ることの問題になります。

with 
-- begin of test data; not part of the solution 
    test_data (license_number) as (
     select '123456789' from dual union all 
     select '123455678' from dual union all 
     select '456789012' from dual union all 
     select '12345'  from dual union all 
     select '123451234' from dual union all 
     select '402023488' from dual union all 
     select '4189012' from dual 
    ), 
-- end of test data; solution (SQL query) continues below this line 
    tokenized (license_number, idx, res) as (
     select license_number, level, 
      mod(10 + to_number(substr(license_number, level, 1)) - level, 10) 
     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, res, grp) as (
     select license_number, res, 
      row_number() over (partition by license_number order by idx) - 
       row_number() over (partition by license_number, res order by idx) 
     from tokenized 
    ), 
    grouped (license_number, res, grp, ct) as (
     select license_number, res, grp, count(*) 
     from  prep 
     group by license_number, res, grp 
    ) 
select license_number, max(ct) as max_count 
from  grouped 
group by license_number 
; 

出力

LICENSE_NUMBER MAX_COUNT 
-------------- --------- 
123455678    5 
123456789    9 
456789012    9 
123451234    5 
4189012     5 
12345     5 
402023488    3 
+0

良い答え。 「私が言葉を使うとき、Humpty Dumptyは、むしろ敬虔な調子で、「それは私がそれを意味するように選択することを意味し、それ以上は意味しない」と言いました。「問題は、あなたが言葉を作れるかどうかは、いろいろなことを意味しているのですか? ""質問は、 "マスターであることになっているハンプティ・ダンプティは言いました。少なくともOracle [MOD(m、n)は負の数に対して正しくないことを文書化する](https://docs.oracle.com/cd/B19306_01/server.102/b14200/functions088.htm)。適切なモジュラスが望まれるならば、それは 'm - n * FLOOR(m/n)'によって計算できます。 –

+0

@BobJarvis - オラクルが三角関数「cos」を意味するために「exp」を使用することを選択した場合、誰もそれを受け入れるとは思わない。しかし、問題はまったく同じです。彼らが負の数に対して異なった振る舞いをしている点を除いて、MODがしていることを「ほとんど」果たす機能を望むなら、それは自由であるが、自由にMODと呼ぶことはできない。 Don Knuthはフォント名に関してMetafontを作成したときにその点を非常に明確にしました。もちろん、ジャケットの多くはちょうど彼が言ったことを無視して、自分自身を含む多くの混乱を引き起こしました。 – mathguy

+0

@BobJarvis ...うわー、私はちょうどドキュメンテーションを見ました、それは本当にばかげています(私のフランス語を赦してください)。関数の名前は "モジュラス"ではなく "モジュロ"です(私の例では10が "モジュラス"です)。 "古典的な"結果を得る方法は、彼らが言うように 'MOD'を使用せず、' FLOOR'を使用します。彼らは例の表でも正しくない古典的なモジュロ値を持っています。彼らは彼ら自身のバージョンとMODの "古典的な"定義との違いを説明するふりをしているにもかかわらず、彼らはまだ "古典的な"ものを理解していない。 MODは常に非ネガティブです。彼らはそれを取得していないようです。 – mathguy

関連する問題