Frage

Ich habe eine Tabelle voller willkürlich formatierter Telefonnummern wie diese

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

Ich muss nach einer Telefonnummer in einem ähnlich beliebigen Format suchen (z. B. 07123456 sollte den Eintrag finden (07) 123 456

In einer normalen Programmiersprache würde ich das so machen, dass ich alle nicht-stelligen Zeichen aus der „Nadel“ entferne, dann jede Zahl im Heuhaufen durchgehe, alle nicht-stelligen Zeichen daraus entferne und dann mit ihnen vergleiche die Nadel, zB (in Rubin)

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

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

Der Haken ist, dass ich das in MySQL tun muss.Es verfügt über eine Vielzahl von String-Funktionen, von denen keine wirklich das zu tun scheint, was ich will.

Derzeit fallen mir 2 „Lösungen“ ein.

  • Hacken Sie eine Franken-Abfrage zusammen CONCAT Und SUBSTR
  • Fügen Sie eine ein % zwischen jedem Zeichen der Nadel (es ist also so: %0%7%1%2%3%4%5%6% )

Allerdings scheint keine dieser Lösungen besonders elegant zu sein.
Hoffentlich kann mir jemand helfen, sonst bin ich möglicherweise gezwungen, die %%%%%%-Lösung zu verwenden

Aktualisieren:Dies erfolgt über einen relativ festen Datensatz mit vielleicht einigen hundert Zeilen.Ich wollte einfach nicht etwas lächerlich Schlimmes tun, worüber zukünftige Programmierer weinen würden.

Wenn der Datensatz wächst, verwende ich den „phoneStripped“-Ansatz.Vielen Dank für all das Feedback!


Könnten Sie eine „Ersetzen“-Funktion verwenden, um alle Vorkommen von „(“, „-“ und „“ zu entfernen?

Es macht mir keine Sorgen, dass das Ergebnis numerisch ist.Die Hauptcharaktere, die ich berücksichtigen muss, sind +, -, (, ) Und spaceWürde diese Lösung also so aussehen?

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

Wäre das nicht furchtbar langsam?

War es hilfreich?

Lösung

Das scheint von Anfang an ein Problem zu sein.Jede Art von Suche erfordert einen Tabellenscan, und wir alle wissen, dass das schlecht ist.

Wie wäre es, wenn Sie eine Spalte mit einem Hash der aktuellen Telefonnummern hinzufügen, nachdem Sie alle Formatierungszeichen entfernt haben?Dann können Sie zumindest die Hashwerte indizieren und einen vollständigen Tabellenscan vermeiden.

Oder ist die Datenmenge gering und wird voraussichtlich nicht stark wachsen?Dann laden Sie vielleicht einfach alle Zahlen in den Client ein und führen dort eine Suche durch.

Andere Tipps

Ich weiß, dass dies eine alte Geschichte ist, aber ich habe sie gefunden, als ich nach einer ähnlichen Lösung suchte.

Ein einfacher REGEXP kann funktionieren:

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

Dies würde mit dem übereinstimmen phonenumber Spalte mit oder ohne Trennzeichen.

Eine unkonventionelle Idee, aber könnten Sie eine „replace“-Funktion verwenden, um alle Instanzen von „(“, „-“ und „“ zu entfernen, und dann eine „isnumeric“-Funktion verwenden, um zu testen, ob die resultierende Zeichenfolge ist eine Zahl?

Dann könnten Sie das Gleiche mit der Telefonnummernzeichenfolge tun, nach der Sie suchen, und sie als ganze Zahlen vergleichen.

Bei Zahlen wie 1800-MATT-ROCKS funktioniert das natürlich nicht.:) :)

Meine Lösung würde in etwa so aussehen, wie John Dyer es gesagt hat.Ich würde eine zweite Spalte hinzufügen (z. B.phoneStripped), das beim Einfügen und Aktualisieren entfernt wird.Indizieren Sie diese Spalte und suchen Sie danach (natürlich nachdem Sie Ihren Suchbegriff entfernt haben).

Sie könnten auch einen Auslöser hinzufügen, um die Spalte automatisch zu aktualisieren, obwohl ich nicht mit Auslösern gearbeitet habe.Aber wie Sie sagten, ist es wirklich schwierig, den MySQL-Code zu schreiben, um die Zeichenfolgen zu entfernen. Daher ist es wahrscheinlich einfacher, dies einfach in Ihrem Client-Code zu tun.

(Ich weiß, das ist spät, aber ich habe gerade angefangen, mich hier umzusehen :)

Ich schlage vor, PHP-Funktionen und keine MySQL-Muster zu verwenden, damit Sie einen Code wie diesen erhalten:

$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 . "' ";

Dies ist ein Problem mit MySQL – die Regex-Funktion kann übereinstimmen, aber nicht ersetzen. Siehe diesen Beitrag für eine mögliche Lösung.

Ist es möglich, eine Abfrage auszuführen, um die Daten neu zu formatieren, damit sie einem gewünschten Format entsprechen, und dann einfach eine einfache Abfrage auszuführen?Auf diese Weise spielt es keine Rolle, ob die anfängliche Neuformatierung langsam ist.

Sehen

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

Es ist nicht wirklich ein Problem, dass der reguläre Ausdruck optisch abschreckend wirken würde, da ihn nur MySQL „sieht“.Beachten Sie, dass anstelle von „+“ (vgl.Beitrag mit [\D] aus dem OP) sollten Sie „*“ im regulären Ausdruck verwenden.

Einige Benutzer sind besorgt über die Leistung (nicht indizierte Suche), aber in einer Tabelle mit 100.000 Kunden wird diese Abfrage, wenn sie über eine Benutzeroberfläche ausgegeben wird, sofort und ohne merkliche Verzögerung zurückgegeben.

MySQL kann auf der Grundlage regulärer Ausdrücke suchen.

Sicher, aber angesichts der willkürlichen Formatierung, wenn mein Heuhaufen enthielt "(027) 123 456" (Denken Sie daran, dass sich die Position von Räumen ändern kann, es könnte aber genauso gut sein 027 12 3456 und ich wollte es mit kombinieren 027123456, müsste mein regulärer Ausdruck daher so sein?

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

(Eigentlich wäre es schlimmer, da das MySQL-Handbuch nicht darauf hinzuweisen scheint, dass es unterstützt wird \D)

Wenn das der Fall ist, entspricht es dann nicht mehr oder weniger meiner %%%%%-Idee?

Nur eine Idee, aber könnten Sie Regex nicht verwenden, um die Zeichen schnell zu entfernen und sie dann damit zu vergleichen, wie @Matt Hamilton vorgeschlagen hat?

Vielleicht sogar eine Ansicht einrichten (ich bin mir bei MySQL bei Ansichten nicht sicher), die alle durch Regex entfernten Telefonnummern in einer einfachen Telefonnummer speichert?

Wehe mir.Am Ende habe ich Folgendes getan:

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

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

Wenn dies regelmäßig vorkommt, wäre es vielleicht eine gute Idee, die Daten so zu ändern, dass sie alle ein Format haben, und dann das Suchformular so einzurichten, dass alle nicht-alphanumerischen Zeichen entfernt werden (wenn Sie Zahlen wie 310-BELL zulassen). .Daten in einem leicht durchsuchbaren Format zu haben, ist die halbe Miete.

Eine mögliche Lösung finden Sie unter http://udf-regexp.php-baustelle.de/trac/

Es muss ein zusätzliches Paket installiert werden, dann können Sie mit REGEXP_REPLACE spielen

Erstellen Sie eine benutzerdefinierte Funktion, um Regex dynamisch zu erstellen.

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 ;

Rufen Sie diese benutzerdefinierte Funktion in Ihrer gespeicherten Prozedur auf.

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

Ich würde Googles verwenden libPhoneNumber um eine Zahl in das E164-Format zu formatieren.Ich würde eine zweite Spalte namens „e164_number“ hinzufügen, um die e164-formatierte Nummer zu speichern und einen Index darauf hinzuzufügen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top