MySQL IN 문의 PDO 바인딩 값
나는 PDO에 꽤 오랫동안 괴로워 한 후 답변을 얻고 싶은 PDO에 문제가 있습니다.
이 예를 보자 :
MySQL IN 문에서 사용하기 위해 ID 배열을 PDO 문에 바인딩하고 있습니다.
배열은 다음과 같습니다. $ values = array (1,2,3,4,5,6,7,8);
데이터베이스 안전 변수는 $ products = implode ( ','$ values);
따라서 $ products 는 값이 '1,2,3,4,5,6,7,8' 인 STRING이 됩니다.
문은 다음과 같습니다.
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (:products)
물론, $ 제품 과 문에 바인딩 할 것 : 제품 .
그러나 문이 컴파일되고 값이 바인딩되면 실제로는 다음과 같습니다.
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN ('1,2,3,4,5,6,7,8')
문제는 명령문에 바인딩하기 위해 쉼표로 구분 된 값으로 준비 했으므로 IN 문 내부의 모든 것을 단일 문자열로 실행하는 것입니다.
내가 실제로 필요한 것은 :
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (1,2,3,4,5,6,7,8)
실제로이를 수행 할 수있는 유일한 방법은 값을 바인딩하지 않고 문자열 자체 내에 배치하는 것입니다.하지만이 작업을 수행하는 더 쉬운 방법이 있어야한다는 것을 확신합니다.
이것은이 질문에서 물었던 것과 같습니다. 배열을 IN () 조건에 바인딩 할 수 있습니까?
답은 in
절 에있는 가변 크기 목록의 경우 쿼리를 직접 구성해야한다는 것입니다.
그러나 를 사용하여 따옴표로 묶인 쉼표로 구분 된 목록을 사용할 수 find_in_set
있지만, 대규모 데이터 세트의 경우 테이블의 모든 값을 char 유형으로 캐스트해야하므로 성능에 상당한 영향을 미칩니다.
예를 들면 :
select users.id
from users
join products
on products.user_id = users.id
where find_in_set(cast(products.id as char), :products)
또는 세 번째 옵션으로 쉼표로 구분 된 목록을 분할하는 사용자 정의 함수를 만들 수 있습니다 (참조 : http://www.slickdev.com/2008/09/15/mysql-query-real-values- 구분 기호로 구분 된 문자열 ID / ). 이는 특히 in(...)
절에 의존하는 쿼리가 많은 경우 세 가지 중에서 가장 좋은 옵션 일 것입니다 .
이 상황을 처리하는 좋은 방법 은 SQL 쿼리의 모든 값에 대해 를 사용 str_pad
하는 것 ?
입니다. 그런 다음 $values
실행할 인수로 값 배열 (귀하의 경우 )을 전달할 수 있습니다 .
$sql = '
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products.id IN ('.str_pad('',count($values)*2-1,'?,').')
';
$sth = $dbh->prepare($sql);
$sth->execute($values);
$user_ids = $sth->fetchAll();
이렇게하면 값을 SQL에 직접 삽입하는 대신 준비된 명령문을 사용하여 더 많은 이점을 얻을 수 있습니다.
PS-주어진 ID를 가진 제품이 사용자 ID를 공유하는 경우 결과는 중복 된 사용자 ID를 반환합니다. 고유 한 사용자 ID 만 원하는 경우 쿼리의 첫 번째 줄을 다음과 같이 변경하는 것이 좋습니다.SELECT DISTINCT users.id
다음과 같은 상황에서 가장 잘 준비된 진술은 다음과 같습니다.
SELECT users.id
FROM users
JOIN products
ON products.user_id = users.id
WHERE products IN (?,?,?,?,?,?,?,?)
그런 다음 값을 반복하고이를 준비된 문에 바인딩하여 바인딩하는 값과 동일한 수의 물음표가 있는지 확인합니다.
$ values 배열 의 값 수 와 동일한 수의 ? 를 IN 에 제공해야합니다.
이것은?의 배열을 다음과 같이 생성하여 쉽게 수행 할 수 있습니다.
$in = join(',', array_fill(0, count($values), '?'));
이 $ in 배열을 IN 절에 사용하십시오.
THis will dynamically provide you with tailor made array of ?s as per your changiing $values array
You can do so very easily. If you have an array of values for your IN() statement EG:
$test = array(1,2,3);
You can simply do
$test = array(1,2,3);
$values = count($test);
$criteria = sprintf("?%s", str_repeat(",?", ($values ? $values-1 : 0)));
//Returns ?,?,?
$sql = sprintf("DELETE FROM table where column NOT IN(%s)", $criteria);
//Returns DELETE FROM table where column NOT IN(?,?,?)
$pdo->sth = prepare($sql);
$pdo->sth->execute($test);
If the expression is based on user input without binding the values with bindValue(), experimental SQL might not be a great choice. But, you can make it safe by checking the syntax of the input with MySQL's REGEXP.
For example:
SELECT *
FROM table
WHERE id IN (3,156)
AND '3,156' REGEXP '^([[:digit:]]+,?)+$'
Here is an example of binding an unknown number of record columns to values for an insert.
public function insert($table, array $data)
{
$sql = "INSERT INTO $table (" . join(',', array_keys($data)) . ') VALUES ('
. str_repeat('?,', count($data) - 1). '?)';
if($sth = $this->db->prepare($sql))
{
$sth->execute(array_values($data));
return $this->db->lastInsertId();
}
}
$id = $db->insert('user', array('name' => 'Bob', 'email' => 'foo@example.com'));
Please try like this:
WHERE products IN(REPLACE(:products, '\'', ''))
Regards
참고URL : https://stackoverflow.com/questions/1586587/pdo-binding-values-for-mysql-in-statement
'developer tip' 카테고리의 다른 글
C # FileStream : 대용량 파일을 쓰기위한 최적의 버퍼 크기? (0) | 2020.11.02 |
---|---|
condition_variable.notify_one ()을 호출하기 전에 잠금을 획득해야합니까? (0) | 2020.11.02 |
번들 이름, 실행 파일 이름, 제품 이름… (0) | 2020.11.02 |
Python의 메시 그리드 함수 (meshgrid mgrid ogrid ndgrid) (0) | 2020.11.02 |
C ++ : 반환 값은 L- 값입니까? (0) | 2020.11.02 |