PHP-IN 절 배열과 함께 PDO 사용
PDO를 IN
사용하여 값에 배열을 사용하는 절이 있는 문을 실행하고 있습니다.
$in_array = array(1, 2, 3);
$in_values = implode(',', $in_array);
$my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (".$in_values.")");
$my_result->execute();
$my_results = $my_result->fetchAll();
위의 코드는 완벽하게 작동하지만 내 질문은 이것이 왜 그렇지 않습니다.
$in_array = array(1, 2, 3);
$in_values = implode(',', $in_array);
$my_result = $wbdb->prepare("SELECT * FROM my_table WHERE my_value IN (:in_values)");
$my_result->execute(array(':in_values' => $in_values));
$my_results = $my_result->fetchAll();
이 코드는 (1) my_value
의 첫 번째 항목과 동일한 항목을 반환 $in_array
하지만 배열의 나머지 항목 (2 및 3) 은 반환 하지 않습니다.
PDO는 그런 것들에 좋지 않습니다. 물음표가있는 문자열을 동적으로 만들고 쿼리에 삽입해야합니다.
$in = str_repeat('?,', count($in_array) - 1) . '?';
$sql = "SELECT * FROM my_table WHERE my_value IN ($in)";
$stm = $db->prepare($sql);
$stm->execute($in_array);
$data = $stm->fetchAll();
쿼리에 다른 자리 표시자가있는 경우 다음 접근 방식을 사용할 수 있습니다 (코드는 내 PDO 자습서 에서 가져옴 ).
array_merge()
함수를 사용 하여 모든 변수를 단일 배열로 조인하고 다른 변수를 쿼리에 나타나는 순서대로 배열 형식으로 추가 할 수 있습니다.
$arr = [1,2,3];
$in = str_repeat('?,', count($arr) - 1) . '?';
$sql = "SELECT * FROM table WHERE foo=? AND column IN ($in) AND bar=? AND baz=?";
$stm = $db->prepare($sql);
$params = array_merge([$foo], $arr, [$bar, $baz]);
$stm->execute($params);
$data = $stm->fetchAll();
명명 된 자리 표시자를 사용하는 경우 명명 된 자리 표시 자의 시퀀스를 만들어야하므로 코드가 조금 더 복잡해집니다 (예 : :id0,:id1,:id2
. 따라서 코드는 다음과 같습니다.
// other parameters that are going into query
$params = ["foo" => "foo", "bar" => "bar"];
$ids = [1,2,3];
$in = "";
foreach ($ids as $i => $item)
{
$key = ":id".$i;
$in .= "$key,";
$in_params[$key] = $item; // collecting values into key-value array
}
$in = rtrim($in,","); // :id0,:id1,:id2
$sql = "SELECT * FROM table WHERE foo=:foo AND id IN ($in) AND bar=:bar";
$stm = $db->prepare($sql);
$stm->execute(array_merge($params,$in_params)); // just merge two arrays
$data = $stm->fetchAll();
다행히도 명명 된 자리 표시 자의 경우 엄격한 순서를 따를 필요가 없으므로 배열을 어떤 순서로든 병합 할 수 있습니다.
PDO 준비 명령문의 변수 대체는 배열을 지원하지 않습니다. 그것은 하나입니다.
배열의 길이에 따라 필요한 자리 표시 자 수를 생성하여이 문제를 해결할 수 있습니다.
$variables = array ('1', '2', '3');
$placeholders = str_repeat ('?, ', count ($variables) - 1) . '?';
$query = $pdo -> prepare ("SELECT * FROM table WHERE column IN($placeholders)");
if ($query -> execute ($variables)) {
// ...
}
PDO가 좋은 솔루션을 제공하지 않는 것 같으므로 대부분 PDO의 API를 따르지만 유용한 기능 http://docs.doctrine-project.org/projects/doctrine-dbal/을 추가하는 DBAL 사용을 고려하는 것이 좋습니다. en / latest / reference / data-retrieval-and-manipulation.html # list-of-parameters-conversion
$stmt = $conn->executeQuery('SELECT * FROM articles WHERE id IN (?)',
array(array(1, 2, 3, 4, 5, 6)),
array(\Doctrine\DBAL\Connection::PARAM_INT_ARRAY)
);
복잡성을 추가하지 않고 데이터베이스와의 상호 작용을 가리지 않는 (대부분의 ORM처럼) 다른 패키지가있을 수 있지만 동시에 작은 일반적인 작업을 조금 더 쉽게 만듭니다.
이렇게 할 수있었습니다. 아이디어는 검색 양식에서 하나의 값이 들어온다는 것입니다. 그들은 무언가를 찾고 있으며 값은 thisField, thatField 또는 someField와 같은 두 필드 중 하나에있을 수 있습니다.
$randomValue = "whatever";
$query = "SELECT * FROM myTable WHERE ((:randomValue in(thisField) or :randomValue in(thatField)) or (someField = :randomValue));";
$statement = $this->mySQL_db->prepare($query);
$statement->bindparam(":randomValue", $randomValue, PDO::PARAM_STR);
$statement->bindparam(":randomValue", $randomValue, PDO::PARAM_STR);
$statement->bindparam(":randomValue", $randomValue, PDO::PARAM_STR);
내가 이해하는 것은 PDO가 $ in_values 내용을 단일 항목으로 취급하고 그에 따라 꽤 할 것이기 때문입니다. PDO는 1,2,3을 단일 문자열로 간주하므로 쿼리는 다음과 같습니다.
SELECT * FROM table WHERE my_value IN ( "1,2,3")
따옴표와 쉼표를 갖도록 내파를 변경하면 문제가 해결 될 것이라고 생각할 수 있지만 그렇지 않습니다. PDO는 따옴표를보고 문자열을 따옴표로 묶는 방법을 변경합니다.
귀하의 쿼리가 첫 번째 값과 일치하는 이유에 대해서는 설명이 없습니다.
나는 방금이 문제에 맞서 작은 래퍼를 코딩했습니다. 내가 확신하는 가장 예쁘거나 최고의 코드는 아니지만 누군가에게 도움이 될 수 있으므로 여기에 있습니다.
function runQuery(PDO $PDO, string $sql, array $params = [])
{
if (!count($params)) {
return $PDO->query($sql);
}
foreach ($params as $key => $values) {
if (is_array($values)) {
// get placeholder from array, e.g. ids => [7,12,3] would be ':ids'
$oldPlaceholder = ':'.$key;
$newPlaceholders = '';
$newParams = [];
// loop through array to create new placeholders & new named parameters
for($i = 1; $i <= count($values); $i++) {
// this gives us :ids1, :ids2, :ids3 etc
$newKey = $oldPlaceholder.$i;
$newPlaceholders .= $newKey.', ';
// this builds an associative array of the new named parameters
$newParams[$newKey] = $values[$i - 1];
}
//trim off the trailing comma and space
$newPlaceholders = rtrim($newPlaceholders, ', ');
// remove the old parameter
unset($params[$key]);
// and replace with the new ones
$params = array_merge($params, $newParams);
// amend the query
$sql = str_replace($oldPlaceholder, $newPlaceholders, $sql);
}
}
$statement = $PDO->prepare($sql);
$statement->execute($params);
return $statement;
}
예를 들어 다음을 전달합니다.
SELECT * FROM users WHERE userId IN (:ids)
array(1) {
["ids"]=>
array(3) {
[0]=>
int(1)
[1]=>
int(2)
[2]=>
int(3)
}
}
된다 :
SELECT * FROM users WHERE userId IN (:ids1, :ids2, :ids3)
array(3) {
[":ids1"]=>
int(1)
[":ids2"]=>
int(2)
[":ids3"]=>
int(3)
}
방탄은 아니지만 내 필요에 대한 유일한 개발자로서 어쨌든 지금까지 괜찮습니다.
Here is a solution for unnamed placeholders (?). If you pass $sql with question mark like "A=? AND B IN(?) " and $args where some of the elements are arrays like [1, [1,2,3]] it will return SQL string with appropriate number of placeholders - "A=? AND B IN(?,?,?)". It needs $args parameter only to find which element is array and how many placeholders it needs. You can find the small PDO extension class with this method that will run your query: https://github.com/vicF/pdo/blob/master/src/PDO.php
public function replaceArrayPlaceholders($sql, $args)
{
$num = 0;
preg_match_all('/\?/', $sql, $matches, PREG_OFFSET_CAPTURE); // Captures positions of placeholders
//echo $matches[0][1][1];
$replacements = [];
foreach($args as $arg) {
if(is_array($arg)) {
$replacements[$matches[0][$num][1]] = implode(',',array_fill(0, count($arg), '?')); // Create placeholders string
}
$num++;
}
krsort($replacements);
foreach($replacements as $position => $placeholders) {
$sql = substr($sql, 0, $position).$placeholders.substr($sql, $position+1); // Replace single placeholder with multiple
}
return $sql;
}
An alternative version of PHP Delusions (@your-common-sense) using closures:
$filter = ["min_price" => "1.98"];
$editions = [1,2,10];
$editions = array_combine(
array_map(function($i){ return ':id'.$i; }, array_keys($editions)),
$editions
);
$in_placeholders = implode(',', array_keys($editions));
$sql = "SELECT * FROM books WHERE price >= :min_price AND edition IN ($in_placeholders)";
$stm = $pdo->prepare($sql);
$stm->execute(array_merge($filter,$editions));
$data = $stm->fetchAll();
ReferenceURL : https://stackoverflow.com/questions/14767530/php-using-pdo-with-in-clause-array
'IT박스' 카테고리의 다른 글
Slack에서 하이퍼 링크 만들기 (0) | 2020.12.26 |
---|---|
다중 블루투스 연결 (0) | 2020.12.26 |
Hive : 테이블의 모든 파티션을 표시하는 방법은 무엇입니까? (0) | 2020.12.25 |
포크 대 스레딩 (0) | 2020.12.25 |
JVM에서 부동 소수점 연산이 모든 플랫폼에서 동일한 결과를 제공합니까? (0) | 2020.12.25 |