Esiste uno standard per memorizzare i numeri di telefono normalizzati in un database?


95

Qual è una buona struttura dati per memorizzare i numeri di telefono nei campi del database? Sto cercando qualcosa che sia abbastanza flessibile da gestire i numeri internazionali e anche qualcosa che consenta di interrogare le varie parti del numero in modo efficiente.

Modifica: solo per chiarire il caso d'uso qui: attualmente memorizzo i numeri in un singolo campo varchar e li lascio proprio come il cliente li ha inseriti. Quindi, quando il numero è richiesto dal codice, lo normalizzo. Il problema è che se voglio interrogare alcuni milioni di righe per trovare numeri di telefono corrispondenti, coinvolge una funzione, come

where dbo.f_normalizenum(num1) = dbo.f_normalizenum(num2)

che è terribilmente inefficiente. Anche le query che cercano cose come il prefisso diventano estremamente complicate quando è solo un singolo campo varchar.

[Modificare]

Le persone hanno dato molti buoni suggerimenti qui, grazie! Come aggiornamento, ecco cosa sto facendo ora: memorizzo ancora i numeri esattamente come sono stati inseriti, in un campo varchar, ma invece di normalizzare le cose in fase di query, ho un trigger che fa tutto ciò che funziona quando i record vengono inseriti o aggiornato. Quindi ho int o bigint per tutte le parti che devo interrogare e quei campi sono indicizzati per rendere le query più veloci.


Una risposta contemporanea alla domanda è qui: stackoverflow.com/a/51761170/968003 . Il succo: usa RFC 3966 per l'archiviazione e libphonenumber per l'analisi / convalida.
Alex Klaus

Risposte:


80

Innanzitutto, oltre al codice del paese, non esiste uno standard reale. La cosa migliore che puoi fare è riconoscere, tramite il prefisso nazionale, a quale nazione appartiene un particolare numero di telefono e trattare il resto del numero in base al formato di quella nazione.

In genere, tuttavia, le apparecchiature telefoniche e simili sono standardizzate in modo da poter quasi sempre suddividere un dato numero di telefono nei seguenti componenti

  • C Codice paese 1-10 cifre (al momento 4 o meno, ma potrebbe cambiare)
  • Un codice di area (provincia / stato / regione) da 0 a 10 cifre (in realtà potrebbe essere necessario un campo regione e un campo area separatamente, anziché un prefisso)
  • E Codice di scambio (prefisso o interruttore) da 0 a 10 cifre
  • L Numero di riga 1-10 cifre

Con questo metodo puoi potenzialmente separare i numeri in modo da trovare, ad esempio, persone che potrebbero essere vicine tra loro perché hanno lo stesso paese, area e codici di scambio. Con i cellulari però non è più qualcosa su cui contare.

Inoltre, all'interno di ogni paese ci sono standard diversi. Puoi sempre contare su un (AAA) EEE-LLLL negli Stati Uniti, ma in un altro paese potresti avere scambi nelle città (AAA) EE-LLL e semplicemente numeri di riga nelle aree rurali (AAA) LLLL. Dovrai iniziare dall'alto in una struttura ad albero di qualche forma e formattarli man mano che hai informazioni. Ad esempio, il codice paese 0 ha un formato noto per il resto del numero, ma per il codice paese 5432 potrebbe essere necessario esaminare il prefisso prima di comprendere il resto del numero.

Potresti anche voler gestire vanitynumeri come(800) Lucky-Guy , il che richiede di riconoscere che, se è un numero statunitense, ci sono troppe cifre (e potresti aver bisogno di una rappresentazione completa per pubblicità o altri scopi) e che negli Stati Uniti le lettere numeri in modo diverso rispetto alla Germania.

Potresti anche voler memorizzare l'intero numero separatamente come campo di testo (con internazionalizzazione) in modo da poter tornare più tardi e riesaminare i numeri quando le cose cambiano, o come backup nel caso in cui qualcuno invii un metodo errato per analizzare il formato di un determinato paese e perde informazioni.


1
Conosci qualche buona convalida JavaScript per provare a convalidare questo?
cmcculloh

6
L'E164 stabilisce limiti molto più severi sulla lunghezza dei numeri: 1-3 per i paesi e una lunghezza massima di 15. Questo non cambierà presto, conoscendo il sistema di telefonia globale.
Rich

Le lunghezze che hai specificato sembrano essere, secondo ITU-T E.164, completamente sbagliate. Sarebbe utile se potessi pubblicare un collegamento al documento degli standard da cui ricavare le tue informazioni o spiegare perché E.164 non si applica.
Abtin Forouzandeh,

5
@ Abtin: non tutti i sistemi telefonici sono conformi a ITU-T E.164. La stragrande maggioranza di loro lo fa, tuttavia, e vale la pena valutare la scelta tra essere conformi agli standard e escludere alcune persone o andare oltre ciò che lo standard dice e accettare tutti. Si noti che E.164 potrebbe essere visto come un sottoinsieme dello schema precedente. Tuttavia, credo che il formato migliore sia quello che l'utente ha immesso esattamente, e quindi un algoritmo di analisi lo tokenizza quando necessario, piuttosto che memorizzare il modulo tokenizzato nel database.
Adam Davis

1) Si può presumere che tutti i numeri internazionali siano conformi ai componenti CAE? 2) Si può presumere che il componente C sia l'unica cosa diversa a seconda di dove si sta chiamando. Ad esempio, il numero statunitense 850-555-1234 ha A = 850 ed E = 555-1234, quindi C = 1 se si chiama dagli Stati Uniti e C = 001 se si chiama dal Regno Unito. Il punto è indipendentemente da dove stai componendo, A ed E non sono dinamici in alcun modo, giusto?
AaronLS

55

KISS - Mi sto stancando di molti siti web statunitensi. Hanno un codice scritto in modo intelligente per convalidare codici postali e numeri di telefono. Quando digito le mie informazioni di contatto norvegesi perfettamente valide, scopro che molto spesso vengono rifiutate.

Lascia una stringa, a meno che tu non abbia bisogno di qualcosa di più avanzato.


Un buon vecchio nvarchar(42)con un po 'di convalida /^+?[0-9 -\.\(\)#*]{4,41}$/funziona molto bene!
SandRock

Sono d'accordo, ma allo stesso tempo non sono d'accordo. In genere si desidera fare qualcosa con quel numero di telefono memorizzato, ad esempio visualizzarlo. Piuttosto che seguire questa strada cercando di analizzarlo abbastanza da visualizzarlo come vuoi, preferisco memorizzarlo in modo normalizzato. Ora non sto dicendo che dovremmo spingerci fino al punto di applicare la parentesi attorno al prefisso. Quello che sto dicendo è che sono tutti numeri senza trattini ecc.
The Muffin Man

4
Credo che i numeri di telefono debbano essere analizzati prima di archiviarli, in modo che possano essere convalidati e archiviati in modo normalizzato. L'analisi e la formattazione internazionale dei numeri di telefono è perfettamente possibile con googlei18n / libphonenumber .
Roel

21

La pagina di Wikipedia su E.164 dovrebbe dirti tutto ciò che devi sapere.


3
no, quello standard definisce solo come sono strutturati i numeri di telefono (sono composti da tre numeri) ma non specifica come questi devono essere visualizzati e / o memorizzati. Ho detto standard? Intendevo Raccomandazione .
BlueWizard

8

Ecco la mia struttura proposta, apprezzerei il feedback:

Il campo del database del telefono dovrebbe essere un varchar (42) con il seguente formato:

CountryCode: numero x estensione

Quindi, ad esempio, negli Stati Uniti, potremmo avere:

1-2125551234x1234

Questo rappresenterebbe un numero USA (prefisso internazionale 1) con prefisso / numero (212) 555 1234 e interno 1234.

Separare il codice del paese con un trattino rende chiaro il codice del paese a qualcuno che sta esaminando i dati. Ciò non è strettamente necessario perché i codici paese sono " codici prefisso " (puoi leggerli da sinistra a destra e sarai sempre in grado di determinare in modo univoco il paese). Tuttavia, poiché i codici paese hanno lunghezze variabili (tra 1 e 4 caratteri al momento) non è possibile individuare facilmente a colpo d'occhio il codice paese a meno che non si utilizzi una sorta di separatore.

Uso una "x" per separare l'estensione perché altrimenti non sarebbe davvero possibile (in molti casi) capire quale fosse il numero e quale fosse l'estensione.

In questo modo puoi memorizzare l'intero numero, incluso prefisso internazionale e interno, in un unico campo di database, che puoi quindi utilizzare per velocizzare le tue query, invece di unirti a una funzione definita dall'utente come hai fatto dolorosamente fino ad ora .

Perché ho scelto un varchar (42)? Bene, prima di tutto, i numeri di telefono internazionali saranno di varia lunghezza, da cui il "var". Sto memorizzando un trattino e una "x", quindi questo spiega il "carattere", e comunque, non farai aritmetica intera sui numeri di telefono (immagino) quindi non ha molto senso provare a usare un tipo numerico . Per quanto riguarda la lunghezza di 42, ho utilizzato la lunghezza massima possibile di tutti i campi sommati, in base alla risposta di Adam Davis, e ho aggiunto 2 per il trattino e la "x".


7

Cerca E.164. Fondamentalmente, memorizzi il numero di telefono come un codice che inizia con il prefisso del paese e un suffisso pbx opzionale. La visualizzazione è quindi un problema di localizzazione. La convalida può anche essere eseguita, ma è anche un problema di localizzazione (in base al prefisso del paese).

Ad esempio, + 12125551212 + 202 verrebbe formattato nella locale en_US come (212) 555-1212 x202. Avrebbe un formato diverso in en_GBo de_DE.

Ci sono un bel po 'di informazioni là fuori su ITU-T E.164, ma è piuttosto criptico.


6

Personalmente mi piace l'idea di memorizzare un numero di telefono varchar normalizzato (ad esempio 9991234567) quindi, ovviamente, formattare quel numero di telefono in linea mentre lo visualizzi.

In questo modo tutti i dati nel database sono "puliti" e privi di formattazione


4

Conservazione

Memorizza i telefoni in RFC 3966 (come +1-202-555-0252, +1-202-555-7166;ext=22). Le principali differenze rispetto a E.164 sono

  • Nessun limite alla lunghezza
  • Supporto delle estensioni

Per ottimizzare le prestazioni delle operazioni di visualizzazione, memorizzare il telefono nel formato nazionale / internazionale accanto al campo RFC 3966.

Non memorizzare il codice del paese in un campo separato a meno che non ne abbia una seria ragione. Perché? Perché non dovresti chiedere il codice del paese sull'interfaccia utente.

Per lo più, le persone entrano nei telefoni mentre li sentono. Ad esempio, se il formato locale inizierà da 0o 8, sarebbe fastidioso per l'utente effettuare la trasformazione del numero nella testa (come, " OK, non digitare" 0 ", scegliere il paese e digitare il resto di ciò che il persona ha detto in questo campo ").

Analisi

Google ti le spalle e puoi convalidare e analizzare qualsiasi numero di telefono utilizzando il loro libphonenumber libreria . Ci sono porte per quasi tutte le lingue.

Quindi lascia che l'utente inserisca " 0449053501" o " 04 4905 3501" o "(04) 4905 3501 ". Lo strumento calcolerà il resto per te.

Guarda la demo ufficiale , per avere un'idea di quanto aiuta.


3

Forse memorizzare le sezioni del numero di telefono in colonne diverse, consentendo voci vuote o nulle?


3

Ok, quindi in base alle informazioni in questa pagina, ecco un inizio su un validatore di numeri di telefono internazionale:

function validatePhone(phoneNumber) {
    var valid = true;
    var stripped = phoneNumber.replace(/[\(\)\.\-\ \+\x]/g, '');    

    if(phoneNumber == ""){
        valid = false;
    }else if (isNaN(parseInt(stripped))) {
        valid = false;
    }else if (stripped.length > 40) {
        valid = false;
    }
    return valid;
}

Liberamente basato su uno script di questa pagina: http://www.webcheatsheet.com/javascript/form_validation.php


2

Lo standard per la formattazione dei numeri è e.164 , dovresti sempre memorizzare i numeri in questo formato. Non si dovrebbe mai consentire il numero di interno nello stesso campo con il numero di telefono, quelli dovrebbero essere memorizzati separatamente. Per quanto riguarda numerico vs alfanumerico, dipende da cosa farai con quei dati.


1

Penso che il testo libero (forse varchar (25)) sia lo standard più utilizzato. Ciò consentirà qualsiasi formato, nazionale o internazionale.

Immagino che il fattore trainante principale potrebbe essere il modo esatto in cui stai interrogando questi numeri e cosa stai facendo con loro.


Questo manca il punto della domanda, che è quello di standardizzare il contenuto dei campi DB per garantire una corrispondenza univoca. Come posso assicurarmi che quando chiedo il numero di telefono 800-555-1212 che corrisponda se l'utente può inserire "(800) 555-1212", "+1.800.555.1212" o qualsiasi altro valore equivalente? Questa è la sfida da affrontare.
Irongaze.com

1

Trovo che la maggior parte dei moduli web consenta correttamente il prefisso internazionale, il prefisso, quindi le restanti 7 cifre, ma quasi sempre dimentico di consentire l'inserimento di un'estensione. Questo finisce quasi sempre per farmi pronunciare parole arrabbiate, dato che al lavoro non abbiamo una receptionist e il mio interno # è necessario per contattarmi.


1

Trovo che la maggior parte dei moduli web consenta correttamente il prefisso internazionale, il prefisso, quindi le restanti 7 cifre, ma quasi sempre dimentico di consentire l'inserimento di un'estensione. Questo finisce quasi sempre per farmi pronunciare parole arrabbiate, dato che al lavoro non abbiamo una receptionist e il mio interno # è necessario per contattarmi.

Dovrei controllare, ma penso che il nostro schema DB sia simile. Abbiamo un codice paese (potrebbe essere predefinito negli Stati Uniti, non sono sicuro), un prefisso, 7 cifre e un'estensione.


1

Che ne dici di memorizzare una colonna di testo libero che mostra una versione user-friendly del numero di telefono, quindi una versione normalizzata che rimuove spazi, parentesi ed espande "+". Per esempio:

Facile da usare: +44 (0) 181 4642542

Normalizzato: 00441814642542


10
Per chi esattamente +44 (0) 181 4642542 dovrebbe essere amichevole? Utenti del Regno Unito che potrebbero non sapere cosa fare con il +44 se non sono abituati a chiamare a livello internazionale, o utenti internazionali che non sapranno che dovrebbero eliminare lo (0)?
Mark Baker

0

Preferirei un campo di testo libero e un campo che contiene una versione puramente numerica del numero di telefono. Lascerei la rappresentazione del numero di telefono all'utente e utilizzerei il campo normalizzato specificamente per i confronti del numero di telefono nelle applicazioni basate su TAPI o quando si cerca di trovare doppie voci in una rubrica telefonica. Ovviamente non fa male fornire all'utente uno schema di accesso che aggiunge intelligenza come campi separati per codice paese (se necessario), prefisso, numero di base ed interno.


0

Da dove prendi i numeri di telefono? Se li ricevi da una parte della rete telefonica, riceverai una stringa di cifre, un tipo di numero e un piano, ad es

441234567890 tipo / piano 0x11 (che significa internazionale E.164)

Nella maggior parte dei casi la cosa migliore da fare è memorizzare tutti questi come sono e normalizzarli per la visualizzazione, sebbene la memorizzazione di numeri normalizzati possa essere utile se si desidera utilizzarli come chiave univoca o simile.


0

Facile da usare: +44 (0) 181864 2542 normalizzato: 00441814642542

Lo (0) non è valido nel formato internazionale. Vedere lo standard ITU-T E.123.

Il formato "normalizzato" non sarebbe utile ai lettori statunitensi poiché utilizzano 011 per l'accesso internazionale.


0

Ho utilizzato 3 modi diversi per memorizzare i numeri di telefono a seconda dei requisiti di utilizzo.

  1. Se il numero viene memorizzato solo per il recupero umano e non verrà utilizzato per la ricerca, viene memorizzato in un campo di tipo stringa esattamente come l'utente l'ha immesso.
  2. Se il campo verrà cercato, eventuali caratteri extra, come +, spazi e parentesi ecc. Verranno rimossi e il numero rimanente verrà memorizzato in un campo di tipo stringa.
  3. Infine, se il numero di telefono verrà utilizzato da un'applicazione per computer / telefono, in questo caso dovrebbe essere inserito e memorizzato come numero di telefono valido utilizzabile dal sistema, questa opzione ovviamente, essendo la più difficile da codificare per.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.