2013-05-21 6 views
0

MySQL 데이터베이스를 쿼리하기 위해 PHP 준비 문을 사용하여 내 웹 사이트에서 고급 검색 페이지를 만들고 있습니다. MyISAM 부울 전체 텍스트 검색을 사용하는 표.PHP/MYSQL - 부울 전체 텍스트 검색 - 정확한 문자열 연산자 ("")는 Prepared Statement와 SQL 쿼리의 결과가 다릅니다.

그것은 구글이 제공하는 고급 검색의 첫 번째 섹션처럼 매우이며, 다음과 같은 기준에 포함

:

  • 정확한 단어 나 문장 (NB는
    • 이 단어의 모든

      :이 문제입니다
    • 이 단어의 상관이 단어의
    • 없음

    나는 각 입력 가치있는 검색 없음)로 제공 e, 문자열 콜렉션의 각 부분을 정리하고 처리 한 다음 준비된 명령문을 통해 mySQL 쿼리를 형성하기위한 적절한 정보를 추가하십시오.

    그래서 다음 검색에 대한 본질 :

    • 모든 - 정확한
    • -
    • 모든 - 씨게이트 도시바
    • 없음 -
    이 문자열로

    겠습니까 출력 :

    seagate* toshiba* 
    

    쿼리는 다음과 같이 될 것이다 : 설명 필드에 아무것도 뒤에 아무것도 "도시바"다음 단어 "씨게이트"모든 행을 나열합니다

    SELECT id, description 
    FROM `items` 
    WHERE MATCH (description) 
    AGAINST ('seagate* toshiba*' IN BOOLEAN MODE) 
    

    . 위와 같이 모든 행을 나열하지만, ​​설명 필드에 "750기가바이트"와 "3백20기가바이트"어떤 행을 제외 할

    -(750gb*) -(320gb*) seagate* toshiba* 
    

    :

    이의 출력을처럼, 잘 작동합니다.

    에 값을 추가하여 "이 단어들은 모두"문자열 우리의 출력을 얻을 것이다 : "위의 모든 행을 나열하지만"16메가바이트 "모두를 포함에서만 다운을 보여 것

    +(16mb*) +(7200rpm*) -(750gb*) -(320gb*) seagate* toshiba* 
    

    을 7200rpm "을 입력하십시오.

    문제가있는 부분은입니다. SQL 쿼리 사용으로

    +(16mb*) +(7200rpm*) -(750gb*) -(320gb*) +("serial ata 600") seagate* toshiba* 
    

    이 문자열을 실행하고 통해 쿼리 결과 : 내가 문자열 "문의 정확한 단어"를 사용하고 "600 ATA 시리얼"값을 추가한다면 우리의 출력을 얻을 것 phpmyadmin 검색 조건과 일치하는 2 행의 결과 집합을 얻습니다.

    그러나 내 웹 사이트에서 이것을 실행하면 + ("serial ata 600")이 완전히 무시된다는 6 개의 결과가 표시됩니다.

    나는 우리의 출력을 얻을 것입니다 수 있도록 "문의 정확한 단어"문자열에 대해서만 값을 입력하는 경우,이 문자열이 포함 된 모든 행을 나열합니다 것을 나타냅니다

    +("serial ata 600") 
    

    결과를 중 " 직렬 "또는"ata "또는"600 "

    mysql에서 동일한 쿼리를 직접 실행하면이 결과는 정확히 "serial ata 600"이라는 단어가 포함 된 모든 행을 나열합니다.

    MySQL definition of this operator에서는 상태 :

    A phrase that is enclosed within double quote (“"”) characters matches 
    only rows that contain the phrase literally, as it was typed. 
    

    이 MySQL은 경우가 있지만 준비된 문으로 PHP와 같은 쿼리를 실행할 때 다른 결과 집합을 반환합니다. 여기

    if ($result = $link->prepare(" 
        SELECT id, description 
        FROM `items` 
        WHERE MATCH (description) 
        AGAINST (? IN BOOLEAN MODE) 
    ")) 
    { 
        $result->bind_param("s", $pattern); 
        ... ETC 
    } 
    

    이 직접하기 전에 $pattern의 출력 : 여기에

    은 준비된 성명

    +("serial ata 600") 
    

    사람이 아마도 내가 어떤 표시되지 않는 한이 문제에 대한 이유를 제시 할 수 PHP와 MySQL 사이에서 일하는 방식에 어떤 차이가 있기 때문입니다.

    문자열은 요청시 생성되는 방법과 관련하여 추가 코드를 제공 할 수 있지만 출력은 예제와 동일합니다.

    의견, 조언, 의견, 의견을 보내 주시면 대단히 감사하겠습니다. 고맙습니다!!

  • 답변

    2

    이것은 작성된 진술 문이 얼굴에 떨어지는 곳입니다. 내부적으로 준비 엔진에 해당하는 일을 할 것입니다 : 당신이 지금

    +(\"serial ata 600\") 
    

    더 이상 3 단어의 인용 문구를 사용하지 않는 동등한를 제공

    $quoted = mysql_real_escape_string('+("serial ata 600")'); 
    

    을, 당신이 보내는 다음과 같은 별도의 단어 :

    +("serial 
    
    ata 
    
    600") 
    

    " 따옴표 SQL 메타 때문이다, 당신은 그들이 메타 문자로 취급 될 필요가있다. 그러나 메타 문자가 있기 때문에 사전 엔진이이를 인용하여 일반 제인 인용 부호로 줄이고 더 이상 검색 구문을 둘러 쌀 수 없습니다. 그들은 검색 구문의 일부가되었습니다. 이 실제로 작동한다면

    모르겠지만, 당신은 준비된 문을 다시 작성해야 할 더 많은 같은

    ... MATCH AGAINST (CONCAT('("', ?, '")')) 
    
    +0

    안녕하세요 마크, 귀하의 의견 너무 감사합니다! 그것은 실제로 그렇게하는 것처럼 보이지만 구현하기가 더 복잡합니다. 그렇게하면서 나는 생각의 사슬이가는 한 올바른 길로 나를 데려갔습니다. 어떻게 확신이 들지는 않지만 문제를 해결할 수있었습니다. 연합을 UTF-8 빈으로 변경하고 모든 값을 어떤 경우에도보다 균일 한 대문자로 변환했습니다. 그러나 이제는 쿼리가 concat을 사용하지 않고 작동하는 것 같습니다. 당신의 도움을 주셔서 감사합니다!!! –

    +0

    '$ quoted = mysql_real_escape_string ('+ (serial "600 \")');'설명 된 것처럼 결과를 생성 한 mysqli_real_escape_string()을 사용하여 실제로 입력 텍스트를 "청소"했다. 그러나'$ pattern'의 결과가 나오기 전에 그 결과는 다시 정리되고, 내가 설명한대로 결과가 생성됩니다. '+ (\ "serial ata 600 \")'의 예에서 설명한 것처럼 큰 따옴표는 이스케이프되어야합니다. 이스케이프 처리가 없으면 결과는 사용자가 제안한 것처럼 3 개의 개별 값을 반환합니다. 더 나은 이해를 주셔서 너무 고마워요! –