mysqlで電話番号を検索する
-
09-06-2019 - |
質問
このような、任意にフォーマットされた電話番号がたくさん入ったテーブルがあります。
027 123 5644
021 393-5593
(07) 123 456
042123456
同様に任意の形式で電話番号を検索する必要があります (例: 07123456
エントリが見つかるはずです (07) 123 456
通常のプログラミング言語でこれを行う方法は、「針」から数字以外の文字をすべて削除し、干し草の山の各数値を調べて、そこから数字以外の文字をすべて削除してから比較することです。針、例: (ルビー)
digits_only = lambda{ |n| n.gsub /[^\d]/, '' }
needle = digits_only[input_phone_number]
haystack.map(&digits_only).include?(needle)
問題は、これを MySQL で行う必要があるということです。これには多くの文字列関数がありますが、どれも私が望むことを実際に行うようには見えません。
現在、私が考える「解決策」は 2 つあります
- フランケンクエリを一緒にハックする
CONCAT
そしてSUBSTR
- を挿入します
%
針の各文字の間 (次のようになります:%0%7%1%2%3%4%5%6%
)
ただし、どちらも特にエレガントな解決策とは思えません。
誰かが助けてくれるといいのですが、そうでないと %%%%%% の解決策を使用せざるを得なくなるかもしれません。
アップデート:これは、おそらく数百行の比較的固定されたデータセットに対して動作します。ただ、将来のプログラマーが泣くようなとんでもなく悪いことはしたくなかったのです。
データセットが大きくなった場合は、「phoneStripped」アプローチを採用します。たくさんのフィードバックありがとうございます!
「replace」関数を使用して、「(」、「-」、および「」のインスタンスを削除できますか?
結果が数値であることは気にしません。私が考慮する必要がある主な登場人物は次のとおりです +
, -
, (
, )
そして space
では、その解決策は次のようになりますか?
SELECT * FROM people
WHERE
REPLACE(REPLACE(REPLACE(REPLACE(REPLACE(phonenumber, '('),')'),'-'),' '),'+')
LIKE '123456'
それはひどく遅いことではないでしょうか?
解決
これは最初から問題があるように見えます。どのような種類の検索を行うにもテーブル スキャンが必要ですが、それが悪いことであることは誰もが知っています。
すべての書式設定文字を削除した後、現在の電話番号のハッシュを含む列を追加してみてはいかがでしょうか。そうすれば、少なくともハッシュ値にインデックスを付けて、本格的なテーブル スキャンを回避できます。
それともデータ量が少なく、あまり増加しないと考えられますか?次に、すべての数値をクライアントに取り込み、そこで検索を実行するだけかもしれません。
他のヒント
これが古い歴史であることは承知していますが、同様の解決策を探していたときに見つけました。
単純な REGEXP が機能する場合があります。
select * from phone_table where phone1 REGEXP "07[^0-9]*123[^0-9]*456"
これは次のものと一致します phonenumber
区切り文字の有無にかかわらず列。
すぐに使えるアイデアですが、「replace」関数を使用して「(」、「-」、および「 "」のインスタンスを削除し、「isnumeric」関数を使用して結果の文字列が正しいかどうかをテストできますか数字ですか?
次に、検索している電話番号文字列に対して同じことを実行し、それらを整数として比較できます。
もちろん、これは 1800-MATT-ROCKS のような番号では機能しません。:)
私の解決策は、ジョン・ダイアーの言ったことに沿ったものになるでしょう。2 番目の列を追加します (例:PhoneStripped) は、挿入および更新時に削除されます。この列にインデックスを付けて検索します (もちろん、検索語を削除した後)。
トリガーを追加して列を自動的に更新することもできますが、私はトリガーを使用したことはありません。しかし、あなたが言ったように、文字列を削除する MySQL コードを記述するのは非常に難しいため、クライアント コードで実行する方が簡単でしょう。
(遅いとは思いますが、ちょうどここを調べ始めたところです:)
mysql パターンではなく php 関数を使用することをお勧めします。そのため、次のようなコードが作成されます。
$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 . "' ";
これは MySQL の問題です。正規表現関数は一致しますが、置換することはできません。 この投稿を参照 考えられる解決策について。
クエリを実行して目的の形式に一致するようにデータを再フォーマットし、その後単純なクエリを実行することは可能ですか?そうすれば、最初の再フォーマットが遅くても、それほど問題にはなりません。
見る
http://www.mfs-erp.org/community/blog/find-phone-number-in-database-format-independent
正規表現が「見える」のは mysql だけなので、見た目がひどいものになることは実際には問題ではありません。「+」の代わりに注意してください (cfr.OP の [\D] を付けて投稿します) 正規表現では '*' を使用する必要があります。
一部のユーザーはパフォーマンス (インデックスなしの検索) を懸念していますが、100,000 人の顧客が含まれるテーブルでは、このクエリはユーザー インターフェイスから発行されると、目立った遅延なくすぐに返されます。
MySQL は正規表現に基づいて検索できます。
確かに、しかし任意のフォーマットを考えると、私の干し草の山に "(027) 123 456"
(スペースの位置は変更される可能性があることに注意してください。同様に簡単に変更される可能性があります) 027 12 3456
と合わせたかったのですが 027123456
, したがって、私の正規表現はこれである必要がありますか?
"^[\D]+0[\D]+2[\D]+7[\D]+1[\D]+2[\D]+3[\D]+4[\D]+5[\D]+6$"
(実際には、mysql マニュアルにはサポートされていないことが示されているため、さらに悪いことになるでしょう) \D
)
そうだとしたら、私の %%%%% の考えとほぼ同じではないでしょうか?
単なるアイデアですが、@Matt Hamilton が提案したように、正規表現を使用して文字をすばやく削除し、それと比較することはできませんか?
おそらく、正規表現によって削除されたすべての電話番号を単純な電話番号に保持するビュー (ビューの mysql はわかりません) をセットアップすることさえできるでしょうか。
悲惨なのは私だ。結局これをやりました:
mre = mobile_number && ('%' + mobile_number.gsub(/\D/, '').scan(/./m).join('%'))
find(:first, :conditions => ['trim(mobile_phone) like ?', mre])
これが定期的に発生するものである場合は、データをすべて 1 つの形式に変更してから、英数字以外を削除するように検索フォームを設定することをお勧めします (310-BELL などの数字を許可する場合)。 。データを検索しやすい形式にできれば、戦いは半分は終わります。
考えられる解決策は http://udf-regexp.php-baustelle.de/trac/
追加のパッケージをインストールする必要がある場合は、REGEXP_REPLACE を使用して遊ぶことができます
ユーザー定義関数を作成して動的に 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 ;
ストアド プロシージャでそのユーザー定義関数を呼び出します。
DECLARE var_PhoneNumberRegex VARCHAR(200);
SET var_PhoneNumberRegex = udfn_GetPhoneRegex('+ 123 555 7890');
SELECT * FROM Customer WHERE phonenumber REGEXP var_PhoneNumberRegex;
私ならGoogleのものを使います lib電話番号 数値を E164 形式にフォーマットします。「e164_number」という 2 番目の列を追加して、e164 形式の数値を保存し、それにインデックスを追加します。