15

このように、任意にフォーマットされた電話番号でいっぱいのテーブルがあります

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つの「解決策」を考えることができます

  • と の franken-query を一緒にハックCONCATするSUBSTR
  • 針のすべての文字の間にa を挿入し%ます (つまり、次のようになります%0%7%1%2%3%4%5%6%:)

ただし、どちらも特に洗練されたソリューションとは思えません。
うまくいけば、誰かが助けてくれるか、%%%%%% ソリューションの使用を余儀なくされるかもしれません

更新: これは、おそらく数百行の比較的固定されたデータ セットに対して動作しています。将来のプログラマーが泣くようなとんでもない悪いことをしたくなかっただけです。

データセットが大きくなった場合は、「phoneStripped」アプローチを採用します。すべてのフィードバックに感謝します!


「置換」機能を使用して、「(」、「-」、および「 」のインスタンスを削除できますか?

結果が数値であることは気にしません。私が考慮する必要がある主な文字は+-(、です。では)space その解決策は次のようになりますか?

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

それはひどく遅くなりませんか?

4

17 に答える 17

13

これは最初から問題のように見えます。どんな種類の検索でもテーブルスキャンが必要になりますが、それは悪いことです。

すべての書式設定文字を取り除いた後、現在の電話番号のハッシュを含む列を追加するのはどうですか。そうすれば、少なくともハッシュ値にインデックスを付けて、全表スキャンを回避できます。

それとも、データの量が少なく、それほど大きくなるとは予想されていませんか?次に、すべての数値をクライアントに吸い込み、そこで検索を実行するだけかもしれません。

于 2008-09-03T01:21:31.373 に答える
2

見る

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

mysqlだけがそれを「見る」ので、正規表現が視覚的にぞっとするようになることは実際には問題ではありません。'+'(OPからの[\ D]を含むcfr。post)の代わりに、正規表現で'*'を使用する必要があることに注意してください。

一部のユーザーはパフォーマンス(インデックス付けされていない検索)を懸念していますが、100000人の顧客がいるテーブルでは、このクエリはユーザーインターフェイスから発行されると、目立った遅延なしにすぐに返されます。

于 2010-03-11T16:27:41.457 に答える
2

すぐに使えるアイデアですが、「replace」関数を使用して「(」、「-」、および「」のインスタンスを取り除き、「isnumeric」関数を使用して結果の文字列が数ですか?

次に、検索している電話番号の文字列に対して同じことを行い、それらを整数として比較できます。

もちろん、これは 1800-MATT-ROCKS のような数字には当てはまりません。:)

于 2008-09-02T23:03:52.497 に答える
2

これは MySQL の問題です。正規表現関数は一致しますが、置き換えることはできません。考えられる解決策については、この投稿を参照してください。

于 2008-09-02T23:16:19.050 に答える
2

目的の形式に一致するようにデータを再フォーマットするクエリを実行してから、単純なクエリを実行することはできますか? そうすれば、最初の再フォーマットが遅くても、実際には問題になりません。

于 2008-09-02T23:18:03.103 に答える
2

私の解決策は、ジョン・ダイアーが言ったことに沿ったものになるでしょう。挿入および更新時に取り除かれる 2 番目の列 (phoneStripped など) を追加します。この列にインデックスを付けて検索します (もちろん、検索用語を削除した後)。

トリガーを使用したことはありませんが、列を自動的に更新するトリガーを追加することもできます。しかし、あなたが言ったように、MySQL コードを記述して文字列を削除するのは非常に難しいため、クライアント コードで行う方がおそらく簡単です。

(これが遅いことはわかっていますが、ここを見回し始めたばかりです:)

于 2008-09-18T18:54:23.897 に答える
2

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 . "' ";
于 2011-01-03T14:13:56.603 に答える
0

正規表現を動的に作成するユーザー定義関数を作成します。

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;
于 2013-09-18T11:16:26.040 に答える
0

MySQL は正規表現に基づいて検索できます。

確かに、しかし任意の書式設定を考えると、干し草の山に"(027) 123 456"(スペースの位置が変わる可能性があることに注意してください。027 12 3456027123456

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

(実際には、mysql のマニュアルがサポートを示していないように見えるため、さらに悪いことになります\D)

だとしたら、私の %%%%% の考えとほぼ同じではないでしょうか?

于 2008-09-02T23:21:17.120 に答える
0

単なるアイデアですが、@Matt Hamiltonが提案したように、正規表現を使用して文字をすばやく取り除き、それと比較することはできませんか?

たぶん、正規表現によって取り除かれたすべての電話番号をプレーンな電話番号に保持するビューを設定することさえできますか?

于 2008-09-02T23:32:11.727 に答える
0

わざわいは私です。私はこれをやってしまった:

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

find(:first, :conditions => ['trim(mobile_phone) like ?', mre])
于 2008-09-02T23:58:03.100 に答える
0

これが定期的に発生する場合は、おそらくデータをすべて 1 つの形式に変更し、検索フォームをセットアップして英数字以外を削除することをお勧めします (310-BELL のような数字を許可する場合)。 . 簡単に検索できる形式のデータを持つことは、戦いの半分です。

于 2008-09-03T00:44:15.423 に答える