Marca
Necesito vincular una matriz de valores a WHERE IN(?)
cláusula. ¿Cómo puedo hacer eso?
Esto funciona:
$mysqli = new mysqli("localhost", "root", "root", "db");
if(!$mysqli || $mysqli->connect_errno)
{
return;
}
$query_str = "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{
$query_prepared->execute();
Pero esto no puedo ponerme a trabajar con un enlazar_param como esto:
$query_str = "SELECT name FROM table WHERE city IN (?)";
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str))
{
$cities = explode(",", $_GET['cities']);
$str_get_cities = "'" . implode("', '", $get_cities) . "'"; // This equals 'Nashville','Knoxville'
$query_prepared->bind_param("s", $cities);
$query_prepared->execute();
¿Qué estoy haciendo mal?
yo también he intentado call_user_func_array
pero parece que no puedo obtener la sintaxis correcta.
Tu sentido común
Desde PHP 8.1, puede pasar una matriz directamente para ejecutar:
$sql = "INSERT INTO users (email, password) VALUES (?,?)"; // sql
$stmt = $mysqli->prepare($sql); // prepare
$stmt->execute([$email, $password]); // execute with data!
Para las versiones anteriores, la tarea es un poco complicada pero factible. Para un caso simple cuando ya tiene una consulta con marcadores de posición, el código sería
$sql = "INSERT INTO users (email, password) VALUES (?,?)"; // sql
$data = [$email, $password]; // put your data into array
$stmt = $mysqli->prepare($sql); // prepare
$stmt->bind_param(str_repeat('s', count($data)), ...$data); // bind array at once
$stmt->execute();
Si bien, como en su caso, tenemos un número arbitrario de marcadores de posición, tendremos que agregar un poco más de código. Tomaré la explicación de mi artículo. Declaración preparada de Mysqli con múltiples valores para la cláusula IN:
- En primer lugar necesitaremos crear una cadena con tantos
?
marca tantos elementos hay en su matriz. Para esto usaríamosstr_repeat()
función que es muy útil para el propósito.- Luego, esta cadena con signos de interrogación separados por comas debe agregarse a la consulta. Aunque es una variable, en este caso es segura ya que contiene solo valores constantes
- entonces esta consulta debe prepararse como cualquier otra consulta
- luego necesitaremos crear una cadena con tipos para usar con bind_param(). Tenga en cuenta que generalmente no hay razón para usar diferentes tipos para las variables vinculadas: mysql las aceptará felizmente como cadenas. Hay casos extremos, pero extremadamente raros. Para el uso diario, siempre puede mantenerlo simple y usar “s” para todo.
str_repeat()
es de nuevo al rescate.- entonces necesitamos vincular nuestros valores de matriz a la declaración. Desafortunadamente, no puedes simplemente escribirlo como una sola variable, así
$stmt->bind_param("s", $array)
solo se permiten variables escalares enbind_param()
. Por suerte, hay un operador de desempaquetado de argumentos eso hace exactamente lo que necesitamos: ¡envía una matriz de valores a una función como si fuera un conjunto de variables distintas!- el resto es como de costumbre: ejecute la consulta, obtenga el resultado y obtenga sus datos.
Así que el código de ejemplo correcto sería
$array = ['Nashville','Knoxville']; // our array
$in = str_repeat('?,', count($array) - 1) . '?'; // placeholders
$sql = "SELECT name FROM table WHERE city IN ($in)"; // sql
$stmt = $mysqli->prepare($sql); // prepare
$types = str_repeat('s', count($array)); //types
$stmt->bind_param($types, ...$array); // bind array at once
$stmt->execute();
$result = $stmt->get_result(); // get the mysqli result
$data = $result->fetch_all(MYSQLI_ASSOC); // fetch the data
Aunque este código es bastante grande, es incomparablemente más pequeño que cualquier otra solución plausible ofrecida en este tema hasta ahora.
-
No entiendo el primer párrafo de tu respuesta. No creo que se suponga que una pregunta proporcione una respuesta, él está buscando una respuesta que usted y otros respondieron. Lo que estaba buscando no era cuántos signos de interrogación necesito agregar, que ya tenía. No pude encontrar una explicación adecuada de bind_param, ya que parece que al documento php.net no le importaba. Quería saber si puedo pasarle una matriz como parámetro.
– Aaaa
17 abr 2020 a las 14:00
-
@AaA hay otro párrafo en mi respuesta, uno menciona un operador de desempaquetado de argumentos. respondio tu pregunta?
– Tu sentido común
18 de abril de 2020 a las 3:39
-
Gracias, el “operador de argumento desempaquetado” fue la respuesta para mí. Esta respuesta resuelve muchas otras preguntas similares con soluciones muy elaboradas.
– Marco Muciño
23 de julio de 2020 a las 22:02
-
esto no funciona
$stmt->bind_param($paramstring, $params );
dameArray to string conversion
cada vez– djack109
31 de diciembre de 2020 a las 17:01
moskito-x
No puedes vincular dos variables con una. signo de interrogación!
Por cada variable que vinculas, necesitas una signo de interrogación.
“bind_param” verifica cada variable si cumple con los requisitos. Posteriormente, el valor de la cadena se coloca entre comillas.
Esto no funcionará:
"SELECT name FROM table WHERE city IN (?)"; ( becomes too )
$q_prepared->bind_param("s", $cities);
"SELECT name FROM table WHERE city IN ('city1,city2,city3,city4')";
debe ser:
"SELECT name FROM table WHERE city IN (?,?,?,?)"; ( becomes too )
$q_prepared->bind_param("ssss", $city1, $city2, $city3, $city4);
"SELECT name FROM table WHERE city IN ('city1', 'city2', 'city3', 'city4')";
$query_prepared->bind_param
cita los parámetros de cadena uno por uno. Y el número de variables y la longitud de los tipos de cadena deben coincidir con los parámetros de la declaración.
$query_str = "SELECT name FROM table WHERE city IN ('Nashville','Knoxville')";
se convertirá
$query_str = "SELECT name FROM table WHERE city IN (?,?)";
Ahora bind_param
debe ser
bind_param("ss", $arg1, $arg2)
con este
$query_str = "SELECT name FROM table WHERE city IN (?)";
y bind_param
con
bind_param("s", $cities)
Usted obtiene:
$query_str = "SELECT name FROM table WHERE city IN ('Nashville,Knoxville')";
Es por eso que una matriz no funciona. La única solución para este hecho es call_user_func_array
.
Si inicializa una declaración, lo siguiente es innecesario:
$query_prepared = $mysqli->stmt_init();
if($query_prepared && $query_prepared->prepare($query_str)) {
Esto es correcto:
$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str)) {
Si no quieres usar call_user_func_array
y solo tiene una pequeña cantidad de argumentos, puede hacerlo con el siguiente código.
[...]
$cities = explode(",", $_GET['cities']);
if (count($cities) > 3) { echo "too many arguments"; }
else
{
$count = count($cities);
$SetIn = "(";
for($i = 0; $i < $count; ++$i)
{
$code .= 's';
if ($i>0) {$SetIn.=",?";} else {$SetIn.="?";}
}
$SetIn .= ")";
$query_str = "SELECT name FROM table WHERE city IN " . $SetIn;
// With two arguments, $query_str will look like
// SELECT name FROM table WHERE city IN (?,?)
$query_prepared = $mysqli->stmt_init();
if($query_prepared->prepare($query_str))
{
if ($count==1) { $query_prepared->bind_param($code, $cities[0]);}
if ($count==2) { $query_prepared->bind_param($code, $cities[0], $cities[1]);}
if ($count==3) { $query_prepared->bind_param($code, $cities[0], $cities[1], $cities[2]);
// With two arguments, $query_prepared->bind_param() will look like
// $query_prepared->bind_param("ss", $cities[0], $cities[1])
}
$query_prepared->execute();
}
[...]
}
Te sugiero que lo pruebes con call_user_func_array
alcanzar.
Busca la solución de nick9v
.
-
sugieres usar
call_user_func_array
pero nunca se muestra aquí cómo hacerlo. =_=’– ggDeGran
24 de octubre de 2015 a las 5:24
-
aquí hay un caso de uso de call_user_func_array y todo el problema explicado pontikis.net/blog/dynamically-bind_param-array-mysqli
– Mochi
11 de abril de 2020 a las 10:09
-
“Se debe tener cuidado al usar mysqli_stmt_bind_param() junto con call_user_func_array(). Tenga en cuenta que mysqli_stmt_bind_param() requiere que los parámetros se pasen por referencia, mientras que call_user_func_array() puede aceptar como parámetro una lista de variables que pueden representar referencias o valores. ” Fuente -> php.net/manual/en/mysqli-stmt.bind-param.php
– Me esfuerzo mucho pero lloro más fuerte
3 de julio de 2020 a las 18:20
miken32
A partir de la versión 8.1 de PHP, ya no se requiere encuadernación. Al igual que con PDO desde la versión 5.0, ahora puede pasar parámetros como una matriz directamente a el método de ejecución.
$mysqli = new mysqli("localhost", "root", "root", "db");
$params = ['Nashville','Knoxville'];
$placeholders = str_repeat('?,', count($params) - 1) . '?'
$query = "SELECT name FROM table WHERE city IN ($placeholders)";
$stmt = $mysqli->prepare($query);
$stmt->execute($params);
Otro ejemplo, si tiene una matriz asociativa con claves que coinciden con los nombres de las columnas:
$mysqli = new mysqli("localhost", "root", "root", "db");
$data = ["bar" => 23, "baz" => "some data"];
$params = array_values($data);
$placeholders = str_repeat('?,', count($params) - 1) . '?'
$columns = implode("`,`", array_keys($data));
$query = "INSERT INTO foo (`$columns`) VALUES ($placeholders)";
$stmt = $mysqli->prepare($query);
$stmt->execute($params);
También vale la pena mencionar que la biblioteca ahora por defecto a lanzar excepciones en caso de errores. Antes de la versión 8.1, este no era el caso.
Cantar la canción
Usar call_user_func_array como esto:
$stmt = $mysqli->prepare("INSERT INTO t_file_result VALUES(?,?,?,?)");
$id = '1111';
$type = 2;
$result = 1;
$path="/root";
$param = array('siis', &$id, &$type, &$result, &$path);
call_user_func_array(array($stmt, 'bind_param'), $param);
$stmt->execute();
printf("%d row inserted. \n", $stmt->effected_rows);
$stmt->close;
mickadoo
Yo también estaba teniendo problemas con esto, y lo hice funcionar con eval
antes de descubrir que la mayoría de la gente está usando call_user_func_array:
$fields = array('model', 'title', 'price'); // Fields in WHERE clause
$values = array( // Type and value for each field
array('s', 'ABCD-1001'),
array('s', '[CD] Test Title'),
array('d', '16.00')
);
$sql = "SELECT * FROM products_info WHERE "; // Start of query
foreach ($fields as $current) { // Build where clause from fields
$sql .= '`' . $current . '` = ? AND ';
}
$sql = rtrim($sql, 'AND '); // Remove last AND
$stmt = $db->prepare($sql);
$types=""; $vals="";
foreach ($values as $index => $current_val) { // Build type string and parameters
$types .= $current_val[0];
$vals .= '$values[' . $index . '][1],';
}
$vals = rtrim($vals, ','); // Remove last comma
$sql_stmt="$stmt->bind_param("" . $types . '",' . $vals . ');'; // Put bind_param line together
eval($sql_stmt); // Execute bind_param
$stmt->execute();
$stmt->bind_result($col1, $col2, $col3, $col4, $col5, $col6); // This could probably also be done dynamically in the same way
while ($stmt->fetch()) {
printf("%s %s %s %s %s %s\n", $col1, $col2, $col3, $col4, $col5, $col6);
}
-
Definitivamente requiere jugar un poco, pero en realidad me gusta mucho esta respuesta. Puede ser un poco más voluminoso que
call_user_func_array
pero honestamente es más fácil de leer y averiguar qué está pasando.–Ethan Moore
20 de julio de 2020 a las 0:35
php 8.2 resolvió casi todo con execute_query
$this->execute_query($query, $parms);
como
$query = "SELECT * FROM users WHERE `email` IN (?) LIMIT 1";
$parms = ["xyx@gmailx.com"];
$this->execute_query($query, $parms);
Recordar ? es marcador de posición y número de ? (marcador de posición) es el mismo número que count($parms) y se puede hacer de varias maneras.
Así que en tu caso debería ser
$query = "SELECT name FROM table WHERE city IN (? , ?)";
$parms = ['Nashville','Knoxville'];
$this->execute_query($query, $parms);
https://www.php.net/manual/en/mysqli.ejecutar-consulta
si desea crear una consulta $ dinámica primero, luego
$query = "SELECT name FROM table WHERE city IN (".implode(",",array_map(fn()=>"?",$parms)).")";
-
Definitivamente requiere jugar un poco, pero en realidad me gusta mucho esta respuesta. Puede ser un poco más voluminoso que
call_user_func_array
pero honestamente es más fácil de leer y averiguar qué está pasando.–Ethan Moore
20 de julio de 2020 a las 0:35
Pedro Mortensen
La forma en que lo hice: prepare la consulta con todos sus signos de interrogación separados, así como la cadena de caracteres.
$cities = array('Nashville', 'Knoxville');
$dibs="";
$query = "SELECT name FROM table WHERE city IN (";
$marks = array();
foreach ($cities as $k => $city) {
// i, s, b, d type based on the variables to bind.
$dibs .= 's';
array_push($marks, '?');
}
$query .= implode(',', $marks) . ')';
Conectar.
$mysql = new mysqli($host, $user, $pass, $dbname);
$statement =
$mysql->prepare($query)
OR die(sprintf(
'Query error (%s) %s', $mysql->errno, $mysql->error
))
;
Luego usas “…” token / puntos suspensivos (documentación) para vincular la matriz.
if ($statement) {
$statement->bind_param($dibs, ...$cities);
$statement->execute();
$statement->close();
}
$mysql->close();
Sé que anula un poco el propósito de vincular para escapar (pero al menos funciona bien con una lista de números enteros, es decir, ID).
$str_get_cities= "'".implode("','", $get_cities)."'";
. ¡¡No utilices comillas!! esto esta hecho adiosbind_param
con la opción “s”!– moskito-x
10 de julio de 2013 a las 14:14
Como otros recomiendan, use call_user_func_array función para vincular los parámetros requeridos a su consulta parametrizada. Solo para enfatizar que acepta parámetros pasados por referencia. Solo pude encontrar fragmentos de código sobre cómo ejecutar consultas parametrizadas con una cantidad dinámica de parámetros para vincular, así que terminé haciendo mi propia función (ver esta publicación). Acepta cualquier consulta SELECCIONAR, ACTUALIZAR, INSERTAR y ELIMINAR parametrizada y me ayuda mucho a hacer dinámicamente cualquier interacción de base de datos MySQL en mi código PHP.
– emboscador
23 de enero de 2017 a las 15:16
Pregunta anterior, clara y completa que pregunta exactamente lo mismo: use una matriz en una declaración preparada de mysqli:
WHERE .. IN(..)
consulta– mickmackusa
3 de abril de 2022 a las 4:59