Форматирайте телефонния номер в Oracle с кода на държавата

Имам изискване да форматирам телефонните номера по следния начин:

  • Без интервали
  • Без специални знаци
  • Премахнете предходната нула - ако съществува код на област
  • Премахнете кода на държавата, ако има такъв, напр. +44

Например това: (03069) 990927 ще стане: 3069990927.

Досега измислих това:

replace(replace(replace(replace(replace(replace(substr(replace(ltrim([VALUE],0), ' ', ''),nvl(length(substr(replace(ltrim([VALUE],0), ' ', ''),11)),0)+1), '-', ''), '(', ''), ')', ''),'/', ''), '.', ''), '+', '')

Има ли по-кратка версия на това, може би с помощта на регулярен израз?

Окончателната версия на този фрагмент ще стане колона в изглед, който ще върне следните колони:

  • Клиентски номер
  • Потребителско име
  • Държава
  • Форматиран телефонен номер

Форматираният телефонен номер ще бъде свързан с международния код за набиране (напр. +44), който е записан в базата данни в таблица - DIALCODE_TAB(COUNTRY_CODE, CODE). По-долу е даден пример, използващ синтаксиса replace по-горе:

CREATE OR REPLACE FORCE VIEW "CUST_PHONE" ("CUSTOMER_ID", "NAME", "COUNTRY", "PHONE_NUMBER") AS 
  select 
    cicm.customer_id, 
    cicm.name, 
    dct.country, 
    dct.code || replace(replace(replace(replace(replace(replace(substr(replace(ltrim(cicm.value,0), ' ',   ''),nvl(length(substr(replace(ltrim(cicm.value,0), ' ', ''),11)),0)+1), '-', ''), '(', ''),   ')', ''),'/', ''), '.', ''), '+', '') phone_number 
from customer_info_comm_method cicm 
join dialcode_tab dct 
  on dct.country_code = customer_info_api.get_country_code(cicm.customer_id) 
where cicm.method_id_db = 'PHONE' 
  --and dct.code || replace(replace(replace(replace(replace(replace(substr(replace(ltrim(cicm.value,0), ' ',   ''),nvl(length(substr(replace(ltrim(cicm.value,0), ' ', ''),11)),0)+1), '-', ''), '(', ''),   ')', ''),'/', ''), '.', ''), '+', '') = [phone_number] 
--in terms of performance this SQL has to be written so that it returns all the records or a specific record when searching for the phone number - very quickly (<10s).
WITH read only;

N.B. Клиентски запис може да има повече от 1 телефонен номер и един и същи телефонен номер може да съществува в повече от 1 клиентски запис.


person pwlm    schedule 06.01.2014    source източник
comment
вижте stackoverflow.com/questions/2947623/   -  person 72DFBF5B A0DF5BE9    schedule 06.01.2014
comment
Регулярен израз, за ​​да се отървете от по-голямата част от шума, ще работи; но колко гъвкави са форматите, с които започвате? Предполагам, че е почти свободен текст. Което означава, че може да се наложи да премахнете международните кодове, преди да търсите водещи нули; и да работи както с нотацията +44, така и със специфичните за страната еквиваленти, като 001 за обаждане до САЩ от Обединеното кралство?   -  person Alex Poole    schedule 06.01.2014
comment
Това е най-вече правилно @Alex, с изключение на това, че обаждането винаги ще бъде от Обединеното кралство.   -  person pwlm    schedule 07.01.2014


Отговори (3)


За начало със забележка: Това работи само ако страната е съхранена другаде за запис и няма телефонни номера без код на област. В противен случай човек не би могъл да възстанови отново пълния телефонен номер.

След това: Как са представени кодовете на държавите във вашите данни? Винаги ли е +44 или може да е 0044? Бъдете внимателни тук. Особено не премахвайте нито една нула (ако приемем, че е регионален код), когато това всъщност е първата от двете нули, представляващи кода на държавата :-)

Тогава: Имате нужда от списък с всички кодове на държави. Да вземем за пример +1441441441. Къде свършва кодът на държавата? (Решение: +1441 е Бермудските острови.)

Що се отнася до „без интервали“ и „без специални знаци“, можете да разрешите това най-добре с regexp_replace.

Така че като цяло задачата не е толкова проста, колкото очевидно сте очаквали да бъде. (Но също не е твърде трудно за изпълнение.)

Бих използвал PL/SQL за това.

Надявам се моите съвети да ви помогнат. Късмет.

РЕДАКТИРАНЕ: Ето какво е необходимо. Все още мисля, че PL/SQL функция ще бъде най-добра тук.

Уверете се, че вашият DIALCODE_TAB съдържа всички необходими кодове на държави.

1. Trim the phone number.
2. Then check if its starts with a country identifyer (+, 00).
2.1. If so: remove that. Remove all non-digits. Look up the country code in your table and remove it.
2.2. If not so: check if it starts with an area identifyer (0).
2.2.1. If so: remove it.
2.2.2. In any case: remove all non-digits.

Това трябва да го направи, при условие че числата са валидни. В Германия понякога хората пишат +49(0)40-123456, което не е валидно, защото или използва код на държава или област, а не и двете в едно и също номер. (0) трябва да се премахне, за да стане номерът валиден.

person Thorsten Kettner    schedule 06.01.2014
comment
Вие сте абсолютно прав @Thorsten. Ще разширя въпроса си допълнително. - person pwlm; 07.01.2014
comment
Съответно разширих отговора си. - person Thorsten Kettner; 09.01.2014

SELECT LTRIM(REGEXP_REPLACE(
                      REGEXP_REPLACE('+44(03069) 990927',
                                    '(\+).([[:digit:]])+'), -- to strip off country code
                     '[^[:alnum:]]'),-- Strip off non-aplanumeric [:digit] if only digit
             '0') -- Remove preceding Zero
FROM DUAL;

Няма да работи за +44990927 (Ако кодът на държавата завършва без интервал или нещо подобно или държавата не започва с +)

person Maheswaran Ravisankar    schedule 06.01.2014

SQL Fiddle

Настройка на схема на Oracle 11g R2:

CREATE TABLE phone_numbers ( phone_number ) AS
          SELECT '(03069) 990927' FROM DUAL
UNION ALL SELECT '+44 1234 567890' FROM DUAL
UNION ALL SELECT '+44(0)1234 567890' FROM DUAL
UNION ALL SELECT '+44(012) 34-567-890' FROM DUAL
UNION ALL SELECT '+44-1234-567-890' FROM DUAL
UNION ALL SELECT '+358-1234567890' FROM DUAL;

Заявка 1:

Ако имате работа само с +44 международни кодове за набиране, тогава бихте могли:

  • използвайте ^\+44|\D, за да премахнете +44 международния код и всички нецифрени знаци; тогава
  • използвайте ^0, за да премахнете водеща нула, ако има такава.

Като този:

SELECT REGEXP_REPLACE(
         REGEXP_REPLACE(
           phone_number,
           '^\+44|\D',
           ''
         ),
         '^0', '' ) AS phone_number
FROM   phone_numbers

Резултати:

|  PHONE_NUMBER |
|---------------|
|    3069990927 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
| 3581234567890 |

(Виждате, че не работи за крайния номер с международен код +358.)

Заявка 2:

Това може да се опрости в един регулярен израз (който е малко по-малко четлив):

SELECT REGEXP_REPLACE(
         phone_number,
         '^(\+44)?\D*0?|\D',
         ''
       ) AS phone_number
FROM   phone_numbers

Резултати:

|  PHONE_NUMBER |
|---------------|
|    3069990927 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
|    1234567890 |
| 3581234567890 |

Заявка 3:

Ако искате да работите с множество международни кодове за набиране, тогава ще трябва да знаете кои са валидни (вижте http://en.wikipedia.org/wiki/List_of_country_calling_codes за списък).

Това е пример за регулярен израз, който ще премахне валидните международни кодове за набиране, започващи с +3, +4 или +5 (ще оставя всички други кодове за набиране, за да кодирате):

SELECT REGEXP_REPLACE(
         phone_number,
         '^(\+(3[0123469]|3[57]\d|38[01256789]|4[013456789]|42[013]|5[09]\d|5[12345678]))?\D*0?|\D',
         ''
       ) AS phone_number
FROM   phone_numbers

Резултати:

| PHONE_NUMBER |
|--------------|
|   3069990927 |
|   1234567890 |
|   1234567890 |
|   1234567890 |
|   1234567890 |
|   1234567890 |

Ако + в началото на международния код за избиране не е задължително, тогава просто заменете \+ (близо до началото на регулярния израз) с \+?.

person MT0    schedule 06.01.2014