문제

다음과 같이 임의로 형식이 지정된 전화번호로 가득 찬 테이블이 있습니다.

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' 접근 방식을 사용하겠습니다.모든 피드백에 감사드립니다!


"(", "-" 및 " "의 인스턴스를 제거하기 위해 "교체" 기능을 사용할 수 있습니까?

결과가 숫자인 것에 대해 걱정하지 않습니다.내가 고려해야 할 주요 인물은 다음과 같습니다. +, -, (, ) 그리고 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-ROCKS와 같은 숫자에는 작동하지 않습니다.:)

내 해결책은 John Dyer가 말한 것과 같은 것입니다.두 번째 열을 추가하겠습니다(예: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)

그렇다면 내 %%%%% 아이디어와 거의 동일하지 않습니까?

단지 아이디어일 뿐이지만 Regex를 사용하여 문자를 빠르게 제거한 다음 @Matt Hamilton이 제안한 것과 비교할 수 없습니까?

정규식에 의해 제거된 모든 전화번호를 일반 전화번호로 유지하는 보기(보기에 대한 mysql은 확실하지 않음)를 설정할 수도 있을까요?

화가 나다.나는 결국 이렇게 했습니다:

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;

나는 구글을 사용할 것이다. lib전화번호 숫자를 E164 형식으로 포맷합니다.e164 형식의 숫자를 저장하고 여기에 색인을 추가하기 위해 "e164_number"라는 두 번째 열을 추가합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top