배열을 IN () 조건에 바인딩 할 수 있습니까?


562

PDO를 사용하여 값 배열을 자리 표시 자에 바인딩 할 수 있는지 궁금합니다. 여기서 유스 케이스는 IN()조건 과 함께 사용할 값 배열을 전달하려고합니다 .

다음과 같이 할 수 있기를 바랍니다.

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

그리고 PDO가 배열의 모든 값을 바인딩하고 인용하도록하십시오.

현재 내가하고있는 일은 :

<?php
$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
foreach($ids as &$val)
    $val=$db->quote($val); //iterate through array and quote
$in = implode(',',$ids); //create comma separated list
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$in.')'
);
$stmt->execute();
?>

확실히 어떤 일을 할 수 있지만 내가 놓친 솔루션이 있는지 궁금하십니까?


3
쿼리에 다른 자리 표시자가있는 경우를 포함하여 배열을 IN () 조건에 바인딩하는 방법에 대한 전체 안내서
Common Sense

질문 이이 질문 의 복제본으로 마감되었습니다 . 이 질문이 4 년 전이고 조회수는 4 배, 답변 수는 3 배, 점수는 12 배이므로 중복 플래그를 취소했습니다. 분명히 최고의 목표입니다.
miken32

2020 년에 이것을보고있는 사람이라면 누구나 github.com/morris/dop 을 사용해보십시오 .
morris4

답변:


262

나는 soulmerge가 옳다고 생각합니다. query-string을 구성해야합니다.

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids), '?'));

$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

수정 : 댄, 당신이 옳았다. 코드를 수정했습니다 (테스트하지는 않았습니다)

편집 : chris (댓글)와 누군가가 문제가되지 않아 foreach-loop ...

(...)
// bindvalue is 1-indexed, so $k+1
foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();

...이 중복 될 수 있으므로 foreach루프와를 $stmt->execute대체 할 수 있습니다 ...

<?php 
  (...)
  $stmt->execute($ids);
?>

(다시 테스트하지 않았다)


7
그것은 흥미로운 해결책이며, ID를 반복하고 PDO :: quote ()를 호출하는 것을 선호하지만 '?'의 색인을 생각합니다. 다른 자리 표시자가 쿼리의 다른 곳에서 먼저 발생하면 자리 표시자가 엉망이됩니까?
Andru

5
예, 문제가 될 것입니다. 그러나이 경우? 대신에 명명 된 매개 변수를 만들 수 있습니다.
stefs

9
오래된 질문이지만 필자가 생각할 가치가있는 것은 $foreachbindValue()필수가 아니라는 것입니다-배열로 실행하십시오. 예 :$stmt->execute($ids);
Chris

2
자리 표시 자 생성은 다음과 같이 수행해야합니다.str_repeat('?,', count($array) - 1). '?';
Xeoncross

8
알지 못하는 사람들을위한 팁, 명명 된 매개 변수와 명명되지 않은 매개 변수를 혼합 할 수 없습니다. 따라서 쿼리에서 명명 된 매개 변수를 사용하는 경우 매개 변수를?로 바꾸고 bindValue 인덱스 오프셋을 보강하여 IN?의 위치가 다른? 매개 변수.
justinl

169

빠른 것을 위해 :

//$db = new PDO(...);
//$ids = array(...);

$qMarks = str_repeat('?,', count($ids) - 1) . '?';
$sth = $db->prepare("SELECT * FROM myTable WHERE id IN ($qMarks)");
$sth->execute($ids);

7
훌륭합니다. 나는 이런 식으로 input_parameters 인수를 사용하려고 생각하지 않았습니다. 쿼리에 IN 목록보다 많은 매개 변수가있는 사용자의 경우 array_unshift 및 array_push를 사용하여 필요한 인수를 배열의 앞과 끝에 추가 할 수 있습니다. 또한, 나는$input_list = substr(str_repeat(',?', count($ids)), 1);
orca

7
시도해 볼 수도 있습니다 str_repeat('?,', count($ids) - 1) . '?'. 하나의 적은 함수 호출.
orca

5
@erfling, 이것은 준비된 진술입니다. 주사는 어디에서 오는가? 실제 증거로 백업 할 수 있다면 기꺼이 정정 해 드리겠습니다.
DonVaughn

5
@erfling, 그렇습니다. 맞습니다. 그리고 params를 바인딩하는 것은이 execute배열에서 id 배열을 보내서 하는 것입니다
DonVaughn

5
아 참으로 어쨌든 배열을 전달하고 있다는 사실을 놓쳤습니다. 이것은 실제로 안전하고 좋은 대답으로 보입니다. 사과드립니다.
erfling

46

IN진술 을 사용하는 것이 중요 합니까? FIND_IN_SETop 를 사용하십시오 .

예를 들어 PDO에는 이와 같은 쿼리가 있습니다.

SELECT * FROM table WHERE FIND_IN_SET(id, :array)

그런 다음 쉼표로 묶인 값 배열 만 바인딩하면됩니다.

$ids_string = implode(',', $array_of_smth); // WITHOUT WHITESPACES BEFORE AND AFTER THE COMMA
$stmt->bindParam('array', $ids_string);

그리고 끝났어.

UPD :이 답변에 대한 의견에서 일부 사람들이 지적한 바와 같이, 몇 가지 문제점을 명시 적으로 언급해야합니다.

  1. FIND_IN_SET테이블에서 인덱스를 사용하지 않고 아직 구현되지 않았습니다 . MYSQL 버그 추적기에서이 레코드를 참조하십시오 . 통지를 해준 @BillKarwin에게 감사합니다.
  2. 검색 할 배열 값으로 쉼표가있는 문자열을 사용할 수 없습니다. implode쉼표 기호를 구분 기호로 사용하므로 올바른 문자열을 구문 분석 할 수 없습니다. 참고로 @VaL에게 감사합니다.

인덱스에 크게 의존하지 않고 검색에 쉼표로 문자열을 사용하지 않으면 위의 솔루션보다 훨씬 쉽고 간단하며 빠릅니다.


25
IN ()은 인덱스를 사용할 수 있으며 범위 스캔으로 계산됩니다. FIND_IN_SET ()은 인덱스를 사용할 수 없습니다.
Bill Karwin

1
그게 요점입니다. 나는 이것을 몰랐다. 그러나 어떤 식 으로든 문제의 성능에 대한 요구 사항이 없습니다. 그렇게 큰 테이블이 아닌 경우 다른 수의 자리 표시 자로 쿼리를 생성하는 별도의 클래스보다 훨씬 낫고 깨끗합니다.
Tim Tonkonogov

11
예, 그러나 요즘 누가 그렇게 큰 테이블을 가지고 있습니까? ;-)
Bill Karwin

3
이 접근법의 또 다른 문제는 쉼표가있는 문자열이 있으면 어떻게됩니까? 예를 들어 ... FIND_IN_SET(description,'simple,search')작동하지만 FIND_IN_SET(description,'first value,text, with coma inside')실패합니다. 따라서이 함수는 "first value", "text", "with coma inside" 원하는 대신 검색 됩니다"first value", "text, with coma inside"
VaL

33

나는 많은 동적 쿼리를 수행하기 때문에 내가 만든 매우 간단한 도우미 함수입니다.

public static function bindParamArray($prefix, $values, &$bindArray)
{
    $str = "";
    foreach($values as $index => $value){
        $str .= ":".$prefix.$index.",";
        $bindArray[$prefix.$index] = $value;
    }
    return rtrim($str,",");     
}

다음과 같이 사용하십시오.

$bindString = helper::bindParamArray("id", $_GET['ids'], $bindArray);
$userConditions .= " AND users.id IN($bindString)";

문자열을 반환하고 쿼리를 실행할 때 필요한 바인딩을 :id1,:id2,:id3업데이트합니다 $bindArray. 쉬운!


6
매개 변수 바인딩 규칙을 위반하지 않기 때문에 훨씬 더 나은 솔루션입니다. 이것은 다른 사람들이 제안한 것처럼 인라인 SQL을 사용하는 것보다 훨씬 안전합니다.
Dimitar Darazhanski

1
신난다. 우아한. 완전한.
칼신

17

EvilRygy의 솔루션이 효과가 없었습니다. Postgres에서 다른 해결 방법을 수행 할 수 있습니다.


$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (string_to_array(:an_array, ','))'
);
$stmt->bindParam(':an_array', implode(',', $ids));
$stmt->execute();

작동하지 않습니다 : ERROR: operator does not exist: integer = text. 최소한 명시적인 캐스팅을 추가해야합니다.
collimarco

17

postgres를위한 매우 깨끗한 방법은 postgres-array ( "{}")를 사용하는 것입니다.

$ids = array(1,4,7,9,45);
$param = "{".implode(', ',$ids)."}";
$cmd = $db->prepare("SELECT * FROM table WHERE id = ANY (?)");
$result = $cmd->execute(array($param));

그것은 SQL 주입을 차단합니까?
Fábio Zangirolami

1
@ FábioZangirolami 그것은 PDO이므로 그렇습니다.
ESCOBAR

예, PDO! 4 년 후. 귀하의 답변은 매우 간단하고 효과적이었습니다. 감사합니다!!!
Fábio Zangirolami

14

내 해결책은 다음과 같습니다.

$total_items = count($array_of_items);
$question_marks = array_fill(0, $total_items, '?');
$sql = 'SELECT * FROM foo WHERE bar IN (' . implode(',', $question_marks ). ')';

$stmt = $dbh->prepare($sql);
$stmt->execute(array_values($array_of_items));

array_values ​​사용에 유의하십시오. 이를 통해 주요 주문 문제를 해결할 수 있습니다.

ID 배열을 병합 한 다음 중복 항목을 제거했습니다. 나는 다음과 같은 것을 가지고 있었다 :

$ids = array(0 => 23, 1 => 47, 3 => 17);

그리고 그것은 실패했다.


이것은 훌륭한 솔루션이었습니다. 쿼리 문자열을 작성하는 것과 달리 바인딩을 올바르게 사용합니다. 나는 이것을 강력히 추천합니다.
Lindylead

참고 : 솔루션을 사용하여 배열의 앞면 또는 뒷면에 항목을 추가 할 수 있으므로 다른 바인딩을 포함 할 수 있습니다. $original_array 원래 배열 앞에 항목 추가 : 원래 배열 array_unshift($original_array, new_unrelated_item); 뒤에 항목 추가 : array_push($original_array, new_unrelated_item); 값이 바인딩되면 new_unrelated 항목이 올바른 위치에 배치됩니다. 이를 통해 배열 및 비 배열 항목을 혼합 할 수 있습니다. `
Lindylead

12

PDO가 stefs가 제안한 것과 비슷한 것을 수행하도록 확장했으며 장기적으로 더 쉬웠습니다.

class Array_Capable_PDO extends PDO {
    /**
     * Both prepare a statement and bind array values to it
     * @param string $statement mysql query with colon-prefixed tokens
     * @param array $arrays associatve array with string tokens as keys and integer-indexed data arrays as values 
     * @param array $driver_options see php documention
     * @return PDOStatement with given array values already bound 
     */
    public function prepare_with_arrays($statement, array $arrays, $driver_options = array()) {

        $replace_strings = array();
        $x = 0;
        foreach($arrays as $token => $data) {
            // just for testing...
            //// tokens should be legit
            //assert('is_string($token)');
            //assert('$token !== ""');
            //// a given token shouldn't appear more than once in the query
            //assert('substr_count($statement, $token) === 1');
            //// there should be an array of values for each token
            //assert('is_array($data)');
            //// empty data arrays aren't okay, they're a SQL syntax error
            //assert('count($data) > 0');

            // replace array tokens with a list of value tokens
            $replace_string_pieces = array();
            foreach($data as $y => $value) {
                //// the data arrays have to be integer-indexed
                //assert('is_int($y)');
                $replace_string_pieces[] = ":{$x}_{$y}";
            }
            $replace_strings[] = '('.implode(', ', $replace_string_pieces).')';
            $x++;
        }
        $statement = str_replace(array_keys($arrays), $replace_strings, $statement);
        $prepared_statement = $this->prepare($statement, $driver_options);

        // bind values to the value tokens
        $x = 0;
        foreach($arrays as $token => $data) {
            foreach($data as $y => $value) {
                $prepared_statement->bindValue(":{$x}_{$y}", $value);
            }
            $x++;
        }

        return $prepared_statement;
    }
}

다음과 같이 사용할 수 있습니다.

$db_link = new Array_Capable_PDO($dsn, $username, $password);

$query = '
    SELECT     *
    FROM       test
    WHERE      field1 IN :array1
     OR        field2 IN :array2
     OR        field3 = :value
';

$pdo_query = $db_link->prepare_with_arrays(
    $query,
    array(
        ':array1' => array(1,2,3),
        ':array2' => array(7,8,9)
    )
);

$pdo_query->bindValue(':value', '10');

$pdo_query->execute();

1
나는 Mark의 의견의 첫 부분을 언급했지만 그가 지적했듯이 같은 토큰 :array이 쿼리의 문자열에 있으면 여전히 안전하지 않습니다 .
Chris

4
미래의 모든 독자를위한 참고 사항 :이 솔루션은 절대 사용해서는 안됩니다. 어설 션은 프로덕션 코드를위한 것이 아닙니다.
Common Sense

1
YCS : 주장의 적합성 이외의 접근법에 대한 귀하의 의견에 관심이있는 피드백에 감사드립니다.
Chris

1
아이디어는 동일하지만 단언이없고 더 간단하고 명시적인 방법이 없습니다. 단 하나의 경우에 대한 예외가 아니라 모든 쿼리를 작성하는 일반적인 방법입니다. 모든 자리 표시 자에는 유형이 표시되어 있습니다. 추측과 같은 작업은 if (is_array($data))불필요하지만 데이터 처리 방법이 더 정확합니다.
당신의 상식

1
의견을 읽는 모든 사람에게 : @Your Common Sense가 언급 한 문제는 개정판 4 에서 수정 되었습니다 .
user2428118

11

보고되지 PDO : 미리 정의 된 상수 가되어 당신이에 나와있는대로해야 더 PDO :: PARAM_ARRAY PDOStatement-> bindParam은

bool PDOStatement :: bindParam (혼합 $ parameter, 혼합 & $ variable [, int $ data_type [, int $ length [, mixed $ driver_options]]])

그래서 나는 그것이 달성 가능하다고 생각하지 않습니다.


1
그게 효과가 있는지 모르겠습니다. 묵시적 인 문자열이 인용되는 것 같습니다.
soulmerge

2
당신은 맞습니다, 따옴표는 이스케이프 처리되지 않습니다. 그 코드를 제거했습니다.

11

다른 매개 변수가 있으면 다음과 같이 할 수 있습니다.

$ids = array(1,2,3,7,8,9);
$db = new PDO(...);
$query = 'SELECT *
            FROM table
           WHERE X = :x
             AND id IN(';
$comma = '';
for($i=0; $i<count($ids); $i++){
  $query .= $comma.':p'.$i;       // :p0, :p1, ...
  $comma = ',';
}
$query .= ')';

$stmt = $db->prepare($query);
$stmt->bindValue(':x', 123);  // some value
for($i=0; $i<count($ids); $i++){
  $stmt->bindValue(':p'.$i, $ids[$i]);
}
$stmt->execute();

큰 답변 주셔서 감사합니다. 이것은 실제로 나를 위해 일한 것 중 유일한 사람이었습니다. 그러나 나는 1 실수를 보았다. 변수 $ rs는 $ stmt 여야합니다
Piet

11

나를 위해 더 섹시한 솔루션은 동적 연관 배열을 구성하고 사용하는 것입니다

// A dirty array sent by user
$dirtyArray = ['Cecile', 'Gilles', 'Andre', 'Claude'];

// we construct an associative array like this
// [ ':name_0' => 'Cecile', ... , ':name_3' => 'Claude' ]
$params = array_combine(
    array_map(
        // construct param name according to array index
        function ($v) {return ":name_{$v}";},
        // get values of users
        array_keys($dirtyArray)
    ),
    $dirtyArray
);

// construct the query like `.. WHERE name IN ( :name_1, .. , :name_3 )`
$query = "SELECT * FROM user WHERE name IN( " . implode(",", array_keys($params)) . " )";
// here we go
$stmt  = $db->prepare($query);
$stmt->execute($params);

하드 실제 시나리오에서 그것을 시도하지 않고 특정 수 있지만 보인다 미세 + 1.
아난 싱 --- 살아 죽을

9

또한이 스레드가 오래되었다는 것을 알고 있지만 곧 사용되지 않을 mysql 드라이버를 PDO 드라이버로 변환하는 동안 동일한 일반 매개 변수와 IN을 동적으로 빌드 할 수있는 기능을 만들어야하는 고유 한 문제가 발생했습니다. 매개 변수 배열. 그래서 나는 이것을 빨리 만들었습니다.

/**
 * mysql::pdo_query('SELECT * FROM TBL_WHOOP WHERE type_of_whoop IN :param AND siz_of_whoop = :size', array(':param' => array(1,2,3), ':size' => 3))
 *
 * @param $query
 * @param $params
 */
function pdo_query($query, $params = array()){

    if(!$query)
        trigger_error('Could not query nothing');

    // Lets get our IN fields first
    $in_fields = array();
    foreach($params as $field => $value){
        if(is_array($value)){
            for($i=0,$size=sizeof($value);$i<$size;$i++)
                $in_array[] = $field.$i;

            $query = str_replace($field, "(".implode(',', $in_array).")", $query); // Lets replace the position in the query string with the full version
            $in_fields[$field] = $value; // Lets add this field to an array for use later
            unset($params[$field]); // Lets unset so we don't bind the param later down the line
        }
    }

    $query_obj = $this->pdo_link->prepare($query);
    $query_obj->setFetchMode(PDO::FETCH_ASSOC);

    // Now lets bind normal params.
    foreach($params as $field => $value) $query_obj->bindValue($field, $value);

    // Now lets bind the IN params
    foreach($in_fields as $field => $value){
        for($i=0,$size=sizeof($value);$i<$size;$i++)
            $query_obj->bindValue($field.$i, $value[$i]); // Both the named param index and this index are based off the array index which has not changed...hopefully
    }

    $query_obj->execute();

    if($query_obj->rowCount() <= 0)
        return null;

    return $query_obj;
}

아직 테스트되지 않았지만 논리가있는 것 같습니다.

그것이 같은 위치에있는 누군가를 돕기를 바랍니다.

편집 : 테스트를 마친 후 다음을 발견했습니다.

  • PDO는 '.'을 좋아하지 않습니다. 그들의 이름으로 (당신이 나에게 물어 보면 다소 바보입니다)
  • bindParam이 잘못된 함수이고 bindValue가 올바른 함수입니다.

코드가 작업 버전으로 편집되었습니다.


8

Schnalle 코드에 대한 약간의 편집

<?php
$ids     = array(1, 2, 3, 7, 8, 9);
$inQuery = implode(',', array_fill(0, count($ids)-1, '?'));

$db   = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN(' . $inQuery . ')'
);

foreach ($ids as $k => $id)
    $stmt->bindValue(($k+1), $id);

$stmt->execute();
?>

//implode(',', array_fill(0, count($ids)-1), '?')); 
//'?' this should be inside the array_fill
//$stmt->bindValue(($k+1), $in); 
// instead of $in, it should be $id

1
count ($ ids) 후에 -1을 제거해야 작동하지 않거나 항상 자리 표시자가 하나 누락되었습니다.
Marcel Burkhard

7

어떤 데이터베이스를 사용하고 있습니까? PostgreSQL에서는 ANY (array)를 사용하는 것이 좋습니다. 따라서 예제를 재사용하려면

<?php
$ids=array(1,2,3,7,8,9);
$db = new PDO(...);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id = ANY (:an_array)'
);
$stmt->bindParam('an_array',$ids);
$stmt->execute();
?>

불행히도 이것은 이식성이 거의 없습니다.

다른 데이터베이스에서는 다른 사람들이 언급했듯이 자신의 마법을 구성해야합니다. 이 논리를 클래스 / 함수에 넣어서 프로그램 전체에서 재사용 할 수 있도록하려고합니다. mysql_query이 시나리오의 주제와 예제에 대한 자세한 내용은 PHP.NET 페이지 의 주석을 살펴보십시오 .


4

같은 문제를 겪은 후에는 더 간단한 해결책을 찾았습니다 (아직 우아하지는 않지만 PDO::PARAM_ARRAY).

주어진 배열 $ids = array(2, 4, 32):

$newparams = array();
foreach ($ids as $n => $val){ $newparams[] = ":id_$n"; }

try {
    $stmt = $conn->prepare("DELETE FROM $table WHERE ($table.id IN (" . implode(", ",$newparams). "))");
    foreach ($ids as $n => $val){
        $stmt->bindParam(":id_$n", intval($val), PDO::PARAM_INT);
    }
    $stmt->execute();

... 등등

따라서 혼합 값 배열을 사용하는 경우 param 유형을 지정하기 전에 값을 테스트하기 위해 더 많은 코드가 필요합니다.

// inside second foreach..

$valuevar = (is_float($val) ? floatval($val) : is_int($val) ? intval($val) :  is_string($val) ? strval($val) : $val );
$stmt->bindParam(":id_$n", $valuevar, (is_int($val) ? PDO::PARAM_INT :  is_string($val) ? PDO::PARAM_STR : NULL ));

그러나 나는 이것을 테스트하지 않았습니다.


4

내가 아는 것처럼 배열을 PDO 문에 바인딩 할 가능성은 없습니다.

그러나 두 가지 일반적인 솔루션이 있습니다.

  1. 위치 자리 표시 자 (?,?,?,?) 또는 명명 된 자리 표시 자 (: id1, : id2, : id3)를 사용하십시오.

    $ whereIn = implode ( ',', array_fill (0, count ($ ids), '?'));

  2. 배열을 먼저 인용

    $ whereIn = array_map (배열 ($ db, 'quote'), $ ids);

두 옵션 모두 좋고 안전합니다. 나는 더 짧기 때문에 두 번째 것을 선호하며 필요한 경우 var_dump 매개 변수를 사용할 수 있습니다. 자리 표시자를 사용하면 값을 바인딩해야하며 결국 SQL 코드는 동일합니다.

$sql = "SELECT * FROM table WHERE id IN ($whereIn)";

마지막으로 중요한 것은 "바운드 변수 수가 토큰 수와 일치하지 않습니다"라는 오류를 피하는 것입니다.

Doctrine 위치 매개 변수를 사용하는 훌륭한 예입니다. 들어오는 매개 변수를 내부적으로 제어 할 수 있기 때문입니다.


4

열에 정수만 포함될 수있는 경우 자리 표시 자없이이 작업을 수행하고 쿼리에 ID를 직접 넣을 수 있습니다. 배열의 모든 값을 정수로 캐스트하면됩니다. 이처럼 :

$listOfIds = implode(',',array_map('intval', $ids));
$stmt = $db->prepare(
    "SELECT *
     FROM table
     WHERE id IN($listOfIds)"
);
$stmt->execute();

이것은 SQL 주입에 취약하지 않아야합니다.


3

여기 내 해결책이 있습니다. 또한 PDO 클래스를 확장했습니다.

class Db extends PDO
{

    /**
     * SELECT ... WHERE fieldName IN (:paramName) workaround
     *
     * @param array  $array
     * @param string $prefix
     *
     * @return string
     */
    public function CreateArrayBindParamNames(array $array, $prefix = 'id_')
    {
        $newparams = [];
        foreach ($array as $n => $val)
        {
            $newparams[] = ":".$prefix.$n;
        }
        return implode(", ", $newparams);
    }

    /**
     * Bind every array element to the proper named parameter
     *
     * @param PDOStatement $stmt
     * @param array        $array
     * @param string       $prefix
     */
    public function BindArrayParam(PDOStatement &$stmt, array $array, $prefix = 'id_')
    {
        foreach($array as $n => $val)
        {
            $val = intval($val);
            $stmt -> bindParam(":".$prefix.$n, $val, PDO::PARAM_INT);
        }
    }
}

위 코드의 샘플 사용법은 다음과 같습니다.

$idList = [1, 2, 3, 4];
$stmt = $this -> db -> prepare("
  SELECT
    `Name`
  FROM
    `User`
  WHERE
    (`ID` IN (".$this -> db -> CreateArrayBindParamNames($idList)."))");
$this -> db -> BindArrayParam($stmt, $idList);
$stmt -> execute();
foreach($stmt as $row)
{
    echo $row['Name'];
}

당신이 무슨 생각을하는지 제게 알려주세요


이것은 아래 user2188977의 답변을 기반으로한다는 것을 잊었습니다.
Lippai Zoltan

getOne ()이 무엇인지 잘 모르겠습니다 .PDO의 일부가 아닌 것 같습니다. 나는 PEAR에서만 그것을 보았습니다. 정확히 무엇을합니까?
Lippai Zoltan

@YourCommonSense 사용자 정의 함수를 답변으로 게시 할 수 있습니까?
무효 성

데이터 형식을 전달하는 것이 좋습니다. BindArrayParam정수로 제한하는 것처럼 연관 배열에서 .
Ian Brindley

2

PDO에서와 같은 배열을 사용할 수 없습니다.

각 값에 대해 매개 변수를 사용하여 문자열을 작성하거나?를 사용해야합니다.

:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5

예를 들면 다음과 같습니다.

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = join(
    ', ',
    array_map(
        function($index) {
            return ":an_array_$index";
        },
        array_keys($ids)
    )
);
$db = new PDO(
    'mysql:dbname=mydb;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM table
     WHERE id IN('.$sqlAnArray.')'
);
foreach ($ids as $index => $id) {
    $stmt->bindValue("an_array_$index", $id);
}

을 계속 사용 bindParam하려면 대신 다음을 수행하십시오.

foreach ($ids as $index => $id) {
    $stmt->bindParam("an_array_$index", $ids[$id]);
}

?자리 표시자를 사용하려면 다음과 같이하십시오.

<?php
$ids = array(1,2,3,7,8,9);
$sqlAnArray = '?' . str_repeat(', ?', count($ids)-1);
$db = new PDO(
    'mysql:dbname=dbname;host=localhost',
    'user',
    'passwd'
);
$stmt = $db->prepare(
    'SELECT *
     FROM phone_number_lookup
     WHERE country_code IN('.$sqlAnArray.')'
);
$stmt->execute($ids);

$ids비어 있는지 모르는 경우 테스트하고 그에 따라 처리해야합니다 (빈 배열을 반환하거나 Null 객체를 반환하거나 예외를 throw하십시오 ...).


0

자리 표시자를 사용하여 매개 변수를 바인딩하는 원래 질문에 더 가깝게 답변하기 위해 조금 더 가져갔습니다.

이 대답은 배열을 통해 두 개의 루프를 만들어 쿼리에 사용해야합니다. 그러나 더 선택적 쿼리를 위해 다른 열 자리 표시자를 갖는 문제를 해결합니다.

//builds placeholders to insert in IN()
foreach($array as $key=>$value) {
    $in_query = $in_query . ' :val_' . $key . ', ';
}

//gets rid of trailing comma and space
$in_query = substr($in_query, 0, -2);

$stmt = $db->prepare(
    "SELECT *
     WHERE id IN($in_query)";

//pind params for your placeholders.
foreach ($array as $key=>$value) {
    $stmt->bindParam(":val_" . $key, $array[$key])
}

$stmt->execute();

0

먼저 "?"의 수를 설정하십시오 쿼리에서 "for"에 의해 다음과 같은 매개 변수를 보냅니다.

require 'dbConnect.php';
$db=new dbConnect();
$array=[];
array_push($array,'value1');
array_push($array,'value2');
$query="SELECT * FROM sites WHERE kind IN (";

foreach ($array as $field){
    $query.="?,";
}
$query=substr($query,0,strlen($query)-1);
$query.=")";
$tbl=$db->connection->prepare($query);
for($i=1;$i<=count($array);$i++)
    $tbl->bindParam($i,$array[$i-1],PDO::PARAM_STR);
$tbl->execute();
$row=$tbl->fetchAll(PDO::FETCH_OBJ);
var_dump($row);
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.