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

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();
?>

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



답변

나는 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);
?>

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


답변

빠른 것을 위해 :

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

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


답변

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에게 감사합니다.

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


답변

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

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. 쉬운!


답변

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();


답변

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));


답변

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

$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);

그리고 그것은 실패했다.