2012-04-01 3 views
3

알고 있습니다.SQLSTATE [HY093] : 잘못된 매개 변수 번호 : 매개 변수가 정의되지 않았습니다 (PDO)

그러나 믿어주세요, 저는이 문제를 해결하는 방법에 대해 꽤 오랫동안 연구 해 왔습니다. 달성하고자하는 것은 PDO와 함께 사용하기위한 PDO MySQL 데이터베이스 래퍼로서 필자의 코드에 통합 할 수 있습니다. 내 주요 문제는 특히 두 개의 함수뿐만 아니라 도달하려고하는 매개 변수의 실제 바인딩에서 유래합니다. 내가 왜 두 개의 기능을 반대하는 이유는 내 노력에도 불구하고 어느 것이 문제를 일으키는 지 파악할 수 없었기 때문입니다. 변수의 나는 var_dump 에드가 변수가 아니라는 것을 확인했습니다. 그것은 다른 것입니다. 여전히, 내가 처음에이 오류가 발생한다는 사실은 무언가가 코드에 잘못되었음을 의미합니다.

별첨 A :fetch($table, $columns, $whereArgs)

이 함수의 목적은 단순히 열을 인출하기위한 것이다. 이것은 작업을 구체적으로 수행하기 위해 필요한 열과 where-clause와 함께 가져올 행의 테이블을 수락하면 수행됩니다. 매개 변수가 제출되면 동적으로 쿼리를 구성하는 하나 또는 두 개의 루프가 호출됩니다.

public function fetch($table, $columns, $whereArgs) 
    { 
     if ($whereArgs === NULL && $columns === NULL) return false; 

     $select = "SELECT "; 
     $where = " WHERE "; 

     $iQuery = 0; 

     $sqlParams = array(); 

     $columnCount = count($columns) - 1; 

     foreach($whereArgs as $key => $value) 
     { 
      $paramKey = sprintf(':%s', $key); 

      $where .= sprintf("`%s`= %s", $key, $paramKey); 

      $sqlParams[ "{$paramKey}" ] = sprintf("%s", $value); 

      if ($iQuery <= $columnCount) 
      { 
       $select .= sprintf('`%s`', $columns[ $iQuery ]); 
       $select .= ', '; 
      } 
      else 
      { 
       $select .= ' '; 
      } 

      ++$iQuery; 
     } 

     if ($iQuery <= $columnCount) 
     { 
      for(; $iQuery < $columnCount; ++$iQuery) 
      { 
       if ($iQuery < $columnCount) 
       { 
        $select .= sprintf('`%s`', $columns[ $iQuery ]); 
        $select .= ', '; 
       } 
       else 
       { 
        $select .= ' '; 
       } 
      } 
     } 

     $select .= sprintf("FROM `%s`", $table); 

     $query = $select . $where; 

     return $this->doQuery($query, $sqlParams, TRUE, QueryType::Row); 
    } 

별첨 B :doQuery($query, $sqlParams, $return = FALSE, $queryType = QueryType::None)

이 함수는 비교적 간단하다 어느있다 (리턴 타입을 반환하는 타입의 신속하게 확인하면서 수행 모두가 결합 값이며, 문을 실행할 '행', '열'또는 '모두'는이 문제의 범위를 벗어나는 클래스 QueryType 클래스에 의해 지정된 다음 요청 된 것을 반환합니다.

protected function doQuery($query, $sqlParams, $return = FALSE, $queryType = QueryType::None) 
    { 
     $statement = $this->mConnection->prepare($query); 

     foreach($sqlParams as $param => $value) 
     { 
      $statement->bindValue($param, $value); 
     } 

     $statement->execute(); 

     if ($return) 
     { 
      switch($queryType) 
      { 
       case QueryType::Row: 
        return $statement->fetch(); 
       case QueryType::Column: 
        return $statement->fetchColumn(); 
       case QueryType::All: 
        return $statement->fetchAll(); 
       case QueryType::None: 
        return $statement; 
       default: 
        return false; 
      } 
     } 

    } 

전시 C :test.php

이 단순히 내가 데이터베이스를 테스트하기 위해 쓴 작은 테스트 스크립트입니다.

$database = new Database('evolve_admin'); 

$res = $database->fetch(
    'evol_users', 
    array('user.id', 'user.email', 'user.firstname'), 
    array('user.email' => '[email protected]') 
); 


var_dump($res); 

기타 의견

내가 내 코드 문제 뭔가가 있다는 것을 배웠다는, 난 그냥 정확히이 될 수 무엇으로 잃었어요. 지금까지 디버깅 기술이 끝나면 이이 문제를 상당히 연구했으며이 오류는 매우 흔한 것 같습니다. 내 주요 목표는이 래퍼가 작동하도록하는 것입니다. 누군가 코드 자체 (특히이 문제의 범위를 벗어나는 것들 포함)에 결함이 있으면 알려주십시오.

이 핸드를 제공하는 사람에게 : 감사합니다.

+0

바인딩 된 매개 변수의 수에 대해 생성 된 SQL을 확인한 다음 그 수가 일치하지 않는 이유를 찾아냅니다. – Corbin

+0

문제는 바인딩되는 단일 매개 변수 만 있다는 것입니다. 필자는 for 루프를 테스트하고 매개 변수를 바인딩합니다. 나는 변수들을 출력 할 수 있는데, 그들은 그들이보아야하는 것처럼 정확하게 보인다. – zeboidlund

+0

아니요, 문제는 매개 변수가 바인딩되지 않습니다 (또는 더 구체적으로 N 매개 변수가 있고 x Corbin

답변

4

나는 당신이 거기에 약간의 공간을 망각하고 생각 : 당신이 $select 하나를 추가 할 때

$where .= sprintf("`%s`= %s", $key, $paramKey); 

당신이 $wher 변수를 사용하여 다음 번이었다.

만약 어디 arg를 하나 더 그 :

WHERE `%s`= %s`%s`= %s`%s`= %s`%s`= %s`%s`= %s 

당신은 당신의 SELECT 세대의 생각과 오류를하지 않았다. 두 개의 동일한 루프가 있으며 선택 생성을 테스트합니다 if ($iQuery <= $columnCount). 하나는 루프와 다른 하나는 외부에 있습니다. 그 용도는 무엇입니까?

편집 : 물론 난이 일어 나니 오류가 이유를 지적하는 것을 잊었다 : array ("{:akey}" => "avalue")은 (내가 문자열로 값을 고려 : 그것은

$sqlParams[ "{$paramKey}" ] = sprintf("%s", $value); 

에 당신은 그 모양을 테이블을 만들 수 있습니다. 은 왜 곱슬 괄호 ({})는 completly 키 이름을 변경 사용 했는가 (:keyname하지 {:keyname}

편집이 있어야한다 : 그래서 여기 좋은 기분이 되었습니까하면 가져 오기 방법의 단순화 된 버전입니다 (. 테스트를 거치지 않아야하지만) 잘 작동

/* 
* $whereArgs default value is an array, so you can call a select 
* without an empty array supplied if you does not have some where clause arguments 
* The separator is how the element will be binded alltogether in the where clause 
*/ 
public function fetch($table, $columns, $whereArgs = array(), $separator= 'AND') 
{ 
    /* We return false, if the columns variable is not set, or is not an array, 
    * or (if it is an array) does not contain anything 
    * or the $whereArgs is not and array (it would mean something bad have been given) 
    */ 
    if (false == isset($columns) || false == is_array($columns) 
      || 0 == count($columns) || false == is_array($whereArgs)) 
    { 
     return false; 
    } 

    $select = "SELECT"; 
    $from = " FROM `$table`"; 
    $where = " WHERE "; 

    /* SELECT generation */ 
    for ($columIt = 0; $columIt < count($columns); $columIt++) 
    { 
     $select .= " " . $columns[$columIt]; 
     // We check if we need to add a ',' 
     if ($columIt+1 < count($columns)) 
     { 
      $select .= ","; 
     } 
    } 

    /* WHERE clause generation */ 
    $sqlParams = array(); 
    $whereIt = 0; 
    foreach($whereArgs as $key => $value) 
    { 
     $stripedKey = preg_replace('/\\./', '_', $key); 
     $where .= " $key= :$stripedKey"; 
     $sqlParams[ ":$stripedKey" ] = "$value"; 
     // We check if we need to add a where separator 
     if ($whereIt +1 < count($whereArgs)) 
     { 
      $select .= " $separator"; 
     } 
     $whereIt++; 

    } 

    /* the generated where clause is only printed if $whereArgs 
    * is not an empty array 
    */ 
    $query = $select . $from . ((0<count($whereArgs))?$where:""); 

    return $this->doQuery($query, $sqlParams, TRUE, QueryType::Row); 
} 

편집 3 '를.' 이 BTW 테스트 샘플을 보지 못했지만, 매개 변수 이름에 포함 할 수없는 문자

편집 4 : 통 더는 그것을 해결 참조하지 않았다, 귀하의 하위 집합에서 '.'을 대체 할 수있는 pre_replace를 추가했습니다. 은 또한 키를 울리는 때 '`'문자가, 쿼리) = 그렇지

`user.email`=:arg 

좋아 아닌가요

user.email=:arg or user.`email`=:arg 

선호하는 실패합니다 제거 (`) 특수 문자를 포함하는 데 사용됩니다 이전처럼 사용했기 때문에 열 이름이 기존 이름과 일치하지 않았습니다.

편집 5 : 키를 제거하여 인수와 인수 배열을 만드는 대신. 카운터 whereIt 당신은 $을 활용하여, 그 오해의 소지가 characheters의 발현을 방지 무엇 안전한 방법을 사용할 수

$where .= " $key= :arg_$whereIt"; 
$sqlParams[ ":arg_$whereIt" ] = "$value"; 

감사

+0

이 오류가있는 이유를 추가 한 편집 된 게시물 – grifos

+0

그래, 고마워하지만 불행히도 내 var_dump()와 똑같은 쿼리가 여전히 출력됩니다. SELECT'user.id', 'user.email','user.firstname','evol_users' 어디'user.email' = : user.email. – zeboidlund

+0

var_dump 또는 $ sqlParams를 반환하는 대상은 무엇입니까? – grifos

0

이 문제는 사실 때문이라고 나는에 있었다 모든 열에 내 테스트 DB에 '.'이 있습니다. '사용자'와 컬럼 이름 사이. 나는 모든 기간을 언더 스코어로 바꾸어서 문제를 해결했고, 그 오류를 제거했다. 쿼리가 여전히 어떤 이유로 작동하지 않지만, 나는 괜찮을 것이라고 확신합니다.

따라서, 예를 들어 :

user.email = user_email.

관련 문제