Tengo curiosidad por saber si es posible vincular una matriz de valores a un marcador de posición utilizando PDO. El caso de uso aquí está intentando pasar una matriz de valores para usar con una IN()
condición.
Me gustaría poder hacer algo como esto:
<?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();
?>
Y haga que PDO enlace y cite todos los valores en la matriz.
En este momento estoy haciendo:
<?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();
?>
¿Qué es lo que sin duda hace el trabajo, pero me pregunto si me falta una solución integrada?
Respuestas:
Creo que soulmerge tiene razón. Tendrás que construir la cadena de consulta.
Solución: Dan, tenías razón. reparó el código (aunque no lo probé)
editar: tanto Chris (comentarios) como alguien en problemas sugirieron que el foreach-loop ...
... podría ser redundante, por lo que el
foreach
bucle y el$stmt->execute
podría reemplazarse por solo ...(de nuevo, no lo probé)
fuente
$foreach
ybindValue()
no es necesario - sólo hay que ejecutar con la matriz. Por ejemplo:$stmt->execute($ids);
str_repeat('?,', count($array) - 1). '?';
Por algo rápido:
fuente
$input_list = substr(str_repeat(',?', count($ids)), 1);
str_repeat('?,', count($ids) - 1) . '?'
. Una llamada a la función menos.execute
una serie de identificadores¿Es tan importante usar la
IN
declaración? Intenta usarFIND_IN_SET
op.Por ejemplo, hay una consulta en PDO como esa
Entonces solo necesita vincular una matriz de valores, implosionados con comas, como este
Y ya está hecho.
UPD: Como algunas personas señalaron en los comentarios a esta respuesta, hay algunos problemas que deberían mencionarse explícitamente.
FIND_IN_SET
no utiliza el índice en una tabla, y todavía no está implementado todavía; consulte este registro en el rastreador de errores MYSQL . Gracias a @BillKarwin por el aviso.implode
usar el símbolo de coma como separador. Gracias a @VaL por la nota.En resumen, si no depende mucho de los índices y no utiliza cadenas con comas para la búsqueda, mi solución será mucho más fácil, más simple y más rápida que las soluciones enumeradas anteriormente.
fuente
... FIND_IN_SET(description,'simple,search')
funcionará, peroFIND_IN_SET(description,'first value,text, with coma inside')
fallará. Por lo tanto, la función buscará en"first value", "text", "with coma inside"
lugar de lo deseado"first value", "text, with coma inside"
Como hago muchas consultas dinámicas, esta es una función auxiliar super simple que hice.
Úselo así:
Devuelve una cadena
:id1,:id2,:id3
y también actualiza los$bindArray
enlaces que necesitará cuando llegue el momento de ejecutar su consulta. ¡Fácil!fuente
La solución de EvilRygy no funcionó para mí. En Postgres puedes hacer otra solución:
fuente
ERROR: operator does not exist: integer = text
. Al menos necesitas agregar un casting explícito.Una manera muy limpia para postgres es usar la matriz postgres ("{}")
fuente
Aquí está mi solución:
Tenga en cuenta el uso de array_values. Esto puede solucionar problemas de pedidos clave.
Estaba fusionando matrices de identificadores y luego eliminando elementos duplicados. Tenía algo como:
Y eso estaba fallando.
fuente
$original_array
Agregar elementos antes de la matriz original:array_unshift($original_array, new_unrelated_item);
Agregue elementos después de la matriz original:array_push($original_array, new_unrelated_item);
cuando los valores están vinculados, los elementos new_unrelacionados se colocarán en las ubicaciones correctas. Esto le permite mezclar elementos de matriz y no matriz. `Extendí PDO para hacer algo similar a lo que sugiere stefs, y a la larga fue más fácil para mí:
Puedes usarlo así:
fuente
:array
está en una cadena en la consulta.if (is_array($data))
innecesarias las conjeturas (como una), pero hace que el procesamiento de datos sea mucho más preciso.En cuanto a PDO: Constantes predefinidas, no hay PDO :: PARAM_ARRAY que necesitaría tal como aparece en PDOStatement-> bindParam
Así que no creo que sea posible.
fuente
Cuando tiene otro parámetro, puede hacer lo siguiente:
fuente
Para mí, la solución más sexy es construir una matriz asociativa dinámica y usarla
fuente
También me doy cuenta de que este hilo es antiguo, pero tuve un problema único en el que, al convertir el controlador mysql que pronto será obsoleto en el controlador PDO, tuve que hacer una función que pudiera construir, dinámicamente, tanto los parámetros normales como los IN desde el mismo param array. Así que rápidamente construí esto:
Todavía no se ha probado, sin embargo, la lógica parece estar allí.
Espero que ayude a alguien en la misma posición,
Editar: Después de algunas pruebas descubrí:
Código editado a la versión de trabajo.
fuente
Una pequeña edición sobre el código de Schnalle
fuente
¿Qué base de datos está utilizando? En PostgreSQL me gusta usar CUALQUIERA (matriz). Entonces, para reutilizar su ejemplo:
Desafortunadamente, esto es bastante no portátil.
En otras bases de datos necesitarás inventar tu propia magia como otros han mencionado. Querrás poner esa lógica en una clase / función para que sea reutilizable en todo tu programa, por supuesto. Eche un vistazo a los comentarios en la
mysql_query
página de PHP.NET para obtener más ideas sobre el tema y ejemplos de este escenario.fuente
Después de pasar por el mismo problema, fui a una solución más simple (aunque todavía no es tan elegante como un
PDO::PARAM_ARRAY
lo sería):dada la matriz
$ids = array(2, 4, 32)
:... y así
Entonces, si está utilizando una matriz de valores mixtos, necesitará más código para probar sus valores antes de asignar el tipo param:
Pero no he probado este.
fuente
Como sé, no hay ninguna posibilidad de vincular una matriz en una declaración PDO.
Pero existen 2 soluciones comunes:
Utilice marcadores de posición posicionales (?,?,?,?) O marcadores de posición con nombre (: id1,: id2,: id3)
$ whereIn = implode (',', array_fill (0, count ($ ids), '?'));
Matriz de cotizaciones anterior
$ whereIn = array_map (array ($ db, 'quote'), $ ids);
Ambas opciones son buenas y seguras. Prefiero el segundo porque es más corto y puedo var_dump parámetros si lo necesito. Usando marcadores de posición, debe vincular valores y al final su código SQL será el mismo.
Y lo último e importante para mí es evitar el error "el número de variables enlazadas no coincide con el número de tokens"
Doctrine es un gran ejemplo del uso de marcadores de posición posicionales, solo porque tiene control interno sobre los parámetros entrantes.
fuente
Si la columna solo puede contener enteros, probablemente podría hacer esto sin marcadores de posición y simplemente poner los identificadores en la consulta directamente. Solo tiene que convertir todos los valores de la matriz en enteros. Me gusta esto:
Esto no debería ser vulnerable a ninguna inyección de SQL.
fuente
Aquí está mi solución. También he extendido la clase PDO:
Aquí hay un ejemplo de uso para el código anterior:
Déjame saber lo que piensas
fuente
BindArrayParam
la matriz asociativa, ya que parece limitar esto a los enteros.No es posible usar una matriz como esa en PDO.
Necesita construir una cadena con un parámetro (¿o usar?) Para cada valor, por ejemplo:
:an_array_0, :an_array_1, :an_array_2, :an_array_3, :an_array_4, :an_array_5
Aquí hay un ejemplo:
Si desea seguir usando
bindParam
, puede hacer esto en su lugar:Si desea utilizar
?
marcadores de posición, puede hacerlo así:Si no sabe si
$ids
está vacío, debe probarlo y manejar ese caso en consecuencia (devolver una matriz vacía, o devolver un objeto nulo, o lanzar una excepción, ...).fuente
Llevé un poco más lejos para obtener la respuesta más cercana a la pregunta original de usar marcadores de posición para vincular los parámetros.
Esta respuesta tendrá que hacer dos bucles a través de la matriz que se utilizará en la consulta. Pero resuelve el problema de tener otros marcadores de posición de columna para consultas más selectivas.
fuente
primero establece el número de "?" en consulta y luego por un "para" enviar parámetros como este:
fuente