سؤال

لدي جدول مليء بأرقام الهواتف المنسقة بشكل عشوائي، مثل هذا

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.إنه يحتوي على مجموعة من وظائف السلسلة، والتي لا يبدو أن أيًا منها يفعل ما أريده حقًا.

حاليًا يمكنني التفكير في "حلين"

  • قم باختراق الاستعلام الصريح معًا CONCAT و SUBSTR
  • أدخل أ % بين كل حرف من الإبرة ( لذلك فهو هكذا: %0%7%1%2%3%4%5%6% )

ومع ذلك، لا يبدو أن أيًا من هذين الحلين يمثل حلولًا أنيقة بشكل خاص.
آمل أن يتمكن شخص ما من المساعدة أو قد أضطر إلى استخدام الحل %%%%%%

تحديث:يعمل هذا على مجموعة ثابتة نسبيًا من البيانات، ربما تحتوي على بضع مئات من الصفوف.أنا فقط لم أرغب في القيام بشيء سيئ للغاية قد يبكي عليه المبرمجون المستقبليون.

إذا نمت مجموعة البيانات فسوف أتبع نهج "phoneStripped".شكرا لكل الردود!


هل يمكنك استخدام وظيفة "استبدال" لإزالة أي مثيلات لـ "("، و"-" و" "،

لست قلقًا بشأن كون النتيجة رقمية.الشخصيات الرئيسية التي أحتاج إلى أخذها في الاعتبار هي +, -, (, ) و 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 عمود مع أو بدون أي أحرف منفصلة.

فكرة مبتكرة، ولكن هل يمكنك استخدام دالة "استبدال" لإزالة أي مثيلات لـ "(" و"-" و" "، ثم استخدام دالة "isnumeric" لاختبار ما إذا كانت السلسلة الناتجة أم لا هو رقم؟

ثم يمكنك أن تفعل الشيء نفسه مع سلسلة أرقام الهاتف التي تبحث عنها ومقارنتها كأعداد صحيحة.

بالطبع، لن ينجح هذا مع أرقام مثل 1800-MATT-ROCS.:)

الحل الذي سأقدمه سيكون على غرار ما قاله جون داير.سأضيف عمودًا ثانيًا (على سبيل المثالphoneStripped) الذي يتم تجريده عند الإدخال والتحديث.قم بفهرسة هذا العمود وابحث عنه (بعد تجريد مصطلح البحث بالطبع).

يمكنك أيضًا إضافة مشغل لتحديث العمود تلقائيًا، على الرغم من أنني لم أعمل مع المشغلات.ولكن كما قلت، من الصعب حقًا كتابة كود MySQL لتجريد السلاسل، لذلك ربما يكون من الأسهل القيام بذلك في كود العميل الخاص بك.

(أعلم أن هذا متأخر، لكنني بدأت للتو في البحث هنا :)

أقترح استخدام وظائف php، وليس أنماط mysql، لذلك سيكون لديك بعض التعليمات البرمجية مثل هذا:

$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 - يمكن أن تتطابق وظيفة regex، لكن لا يمكن استبدالها. انظر هذا المنصب لحل ممكن.

هل من الممكن تشغيل استعلام لإعادة تنسيق البيانات لتتناسب مع التنسيق المطلوب ثم تشغيل استعلام بسيط فقط؟بهذه الطريقة، حتى لو كانت عملية إعادة التنسيق الأولية بطيئة، فلا يهم حقًا.

يرى

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

إنها ليست مشكلة حقًا أن يصبح التعبير العادي مروعًا بصريًا، حيث أن MySQL فقط هو الذي "يراه".لاحظ أنه بدلاً من "+" (راجع.نشر مع [\D] من OP) يجب عليك استخدام "*" في التعبير العادي.

يشعر بعض المستخدمين بالقلق بشأن الأداء (البحث غير المفهرس)، ولكن في جدول يضم 100000 عميل، يعود هذا الاستعلام فورًا، عند إصداره من واجهة مستخدم، دون تأخير ملحوظ.

يمكن لـ 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)

إذا كان الأمر كذلك، أليس هذا مشابهًا تقريبًا لفكرتي %%%%%؟

مجرد فكرة، ولكن ألا يمكنك استخدام Regex لإزالة الشخصيات بسرعة ثم مقارنتها بما اقترحه @Matt Hamilton؟

ربما حتى قم بإعداد طريقة عرض (لست متأكدًا من mysql في طرق العرض) من شأنها أن تحتوي على جميع أرقام الهواتف التي تم تجريدها بواسطة regex إلى رقم هاتف عادي؟

ويحي.انتهى بي الأمر بفعل هذا:

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

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

إذا كان هذا شيئًا سيحدث بشكل منتظم، فربما يكون تعديل البيانات لتكون بتنسيق واحد ثم إعداد نموذج البحث لإزالة أي أرقام غير أبجدية رقمية (إذا سمحت بأرقام مثل 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;

سأستخدم جوجل libPhoneNumber لتنسيق رقم إلى تنسيق E164.أود إضافة عمود ثانٍ يسمى "e164_number" لتخزين الرقم المنسق e164 وإضافة فهرس عليه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top