Pregunta

Tengo una tabla que se llena de forma arbitraria formato de los números de teléfono, como este

027 123 5644
021 393-5593
(07) 123 456
042123456

Necesito buscar un número de teléfono en un igualmente arbitraria formato ( por ejemplo, 07123456 debe encontrar la entrada (07) 123 456

La forma en que me gustaría hacerlo en un normal del lenguaje de programación es despojar a todos los no-dígito personajes de la 'aguja', y luego ir a través de cada número en el pajar, tira todos los no-dígito personajes fuera de él, a continuación, compare contra de la aguja, por ejemplo, (en ruby)

digits_only = lambda{ |n| n.gsub /[^\d]/, '' }

needle = digits_only[input_phone_number]
haystack.map(&digits_only).include?(needle)

El problema es, que tengo que hacer esto en MySQL.Tiene un sinfín de funciones de cadena, ninguno de los cuales parece realmente hacer lo que quiero.

Actualmente no puedo pensar en 2 'soluciones'

  • Hackear un franken-consulta de CONCAT y SUBSTR
  • Insertar un % entre todos los personajes de la aguja ( así es como este: %0%7%1%2%3%4%5%6% )

Sin embargo, ninguno de estos parece muy elegante soluciones.
Espero que alguien pueda ayudar o me podrían verse obligados a utilizar los %%%%%% solución

Actualización:Esta es la operación a través de un relativamente fijos conjunto de datos, con tal vez un par de cientos de filas.Yo no quiero hacer algo ridículamente malo que los futuros programadores iba a llorar más.

Si el conjunto de datos crece voy a tomar el 'phoneStripped' enfoque.Gracias por todos los comentarios!


se puede utilizar una función "reemplazar" a eliminar todas las instancias de "(", "-" y " ",

No estoy preocupado por el resultado numérico.Los personajes principales necesito a tener en cuenta son +, -, (, ) y space Por lo tanto sería la solución de este aspecto?

SELECT * FROM people 
WHERE 
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(phonenumber, '('),')'),'-'),' '),'+')
LIKE '123456'

No se que sería terriblemente lento?

¿Fue útil?

Solución

Esto se ve como un problema desde el inicio.Cualquier tipo de búsqueda que hagas va a requerir un examen de la tabla y todos sabemos que eso es malo.

¿Cómo sobre la adición de una columna con un hash de los actuales números de teléfono después de que se eliminen todos los caracteres de formato.A continuación, puede, al menos, el índice de los valores de hash y evitar por completo de exploración de la tabla.

O es la cantidad de datos pequeños y no se espera que crezca mucho?Entonces, tal vez sólo chupar todos los números en el cliente y ejecutar una búsqueda allí.

Otros consejos

Sé que esto es historia antigua, pero he encontrado mientras buscaba una solución similar.

Un simple REGEXP puede trabajar:

select * from phone_table where phone1 REGEXP "07[^0-9]*123[^0-9]*456"

Esto coincidiría con la phonenumber columna con o sin separación de caracteres.

Un fuera-de-la-caja idea, pero se puede utilizar una función "reemplazar" a eliminar todas las instancias de "(", "-" y "" y, a continuación, utilizar un "isnumeric" función para comprobar si la cadena resultante es un número?

Entonces usted podría hacer lo mismo con el número de teléfono de la cadena que desea buscar y comparar como enteros.

Por supuesto, esto no funciona para los números como 1800-MATT-las ROCAS.:)

Mi solución sería algo a lo largo de las líneas de lo que John Dyer dijo.Me gustaría añadir una segunda columna (por ejemplo,phoneStripped) que se desnudaron en insert y update.El índice de esta columna y buscar en ella (después de despojar de su término de búsqueda, por supuesto).

También puedes agregar un disparador para actualizar automáticamente la columna, aunque no he trabajado con los desencadenadores.Pero como usted dijo, es realmente difícil escribir el código de MySQL a la tira de las cuerdas, por lo que es probablemente más fácil hacerlo en su código de cliente.

(Sé que es tarde, pero acabo de empezar a mirar por aquí :)

yo sugiero utilizar las funciones de php, y no de mysql patrones, por lo que tendrá algo de código como este:

$tmp_phone = '';
for ($i=0; $i < strlen($phone); $i++)
   if (is_numeric($phone[$i]))
       $tmp_phone .= '%'.$phone[$i];
$tmp_phone .= '%';
$search_condition .= " and phone LIKE '" . $tmp_phone . "' ";

Este es un problema con MySQL - la expresión de la función pueden coincidir, pero no puede reemplazar. Ver este post una posible solución.

Es posible ejecutar una consulta para volver a formatear los datos para que coincida con un formato que desee y, a continuación, sólo tiene que ejecutar una consulta simple?De esta forma, incluso si la primera formatear es más lento que en realidad no importa.

Ver

http://www.mfs-erp.org/community/blog/find-phone-number-in-database-format-independent

No es realmente un problema que la expresión regular que se convertiría visualmente atroz, ya que sólo mysql "ve" es.Tenga en cuenta que en lugar de '+' (cfr.post con [\D] de la OP) se debe utilizar '*' en la expresión regular.

Algunos usuarios están preocupados por el rendimiento (no indizada de búsqueda), pero en una tabla con 100000 clientes, esta consulta, cuando se emite desde una interfaz de usuario devuelve inmediatamente, sin retraso notable.

MySQL puede buscar basadas en expresiones regulares.

Seguro, pero dada la arbitrariedad del formato, si mi pajar contenidos "(027) 123 456" (tener en cuenta la posición de los espacios puede cambiar, se podría fácilmente ser 027 12 3456 y yo quería hacerla coincidir con 027123456, mi regex por lo tanto necesitan ser esto?

"^[\D]+0[\D]+2[\D]+7[\D]+1[\D]+2[\D]+3[\D]+4[\D]+5[\D]+6$"

(en realidad sería peor, ya que el manual de mysql no parece indicar que se apoya \D)

Si ese es el caso, no es más o menos el mismo que el de mi %%%%% idea?

Es solo una idea, pero no podía usar Regex rápidamente tira de los caracteres y, a continuación, compare contra que como @Matt Hamilton sugirió?

Tal vez incluso establecer un punto de vista (no estoy seguro de mysql en vistas) que se mantenga todos los números de teléfono despojados por regex a un simple número de teléfono?

Ay de mí.Terminé haciendo esto:

mre = mobile_number && ('%' + mobile_number.gsub(/\D/, '').scan(/./m).join('%'))

find(:first, :conditions => ['trim(mobile_phone) like ?', mre])

si esto es algo que va a ocurrir en una base regular, tal vez la modificación de los datos a ser todo un formato y, a continuación, configurar el formulario de búsqueda de tiras de cualquier carácter no alfanumérico (si lo permiten los números como 310-BELL) sería una buena idea.Tener los datos en un buscar fácilmente el formato es la mitad de la batalla.

una posible solución puede encontrarse en:http://udf-regexp.php-baustelle.de/trac/

paquete adicional necesita ser instalado, entonces usted puede jugar con REGEXP_REPLACE

Crear una función definida por el usuario a crea dinámicamente Regex.

DELIMITER //

CREATE FUNCTION udfn_GetPhoneRegex
(   
    var_Input VARCHAR(25)
)
RETURNS VARCHAR(200)

BEGIN
    DECLARE iterator INT          DEFAULT 1;
    DECLARE phoneregex VARCHAR(200)          DEFAULT '';

    DECLARE output   VARCHAR(25) DEFAULT '';


   WHILE iterator < (LENGTH(var_Input) + 1) DO
      IF SUBSTRING(var_Input, iterator, 1) IN ( '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ) THEN
         SET output = CONCAT(output, SUBSTRING(var_Input, iterator, 1));
      END IF;
      SET iterator = iterator + 1;
   END WHILE;
    SET output = RIGHT(output,10);
    SET iterator = 1;
    WHILE iterator < (LENGTH(output) + 1) DO
         SET phoneregex = CONCAT(phoneregex,'[^0-9]*',SUBSTRING(output, iterator, 1));
         SET iterator = iterator + 1;
    END WHILE;
    SET phoneregex = CONCAT(phoneregex,'$');
   RETURN phoneregex;
END//
DELIMITER ;

Llamar a esa Función Definida por el Usuario en el procedimiento almacenado.

DECLARE var_PhoneNumberRegex        VARCHAR(200);
SET var_PhoneNumberRegex = udfn_GetPhoneRegex('+ 123 555 7890');
SELECT * FROM Customer WHERE phonenumber REGEXP var_PhoneNumberRegex;

Yo uso el de Google libPhoneNumber para dar formato a un número de formato E164.Me gustaría añadir una segunda columna llamada "e164_number" para guardar la e164 formato de número y añadir un índice en ella.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top