Pasar un array a una consulta usando una cláusula WHERE


Dado un array de ids $galleries = array(1,2,5) Quiero tener una consulta SQL que use los valores del array en su cláusula WHERE como:

SELECT *
FROM galleries
WHERE id = /* values of array $galleries... eg. (1 || 2 || 5) */

¿Cómo puedo generar esta cadena de consulta para usarla con MySQL?

Author: Braiam, 2009-05-25

18 answers

¡CUIDADO! Esta respuesta contiene una vulnerabilidad severa de inyección SQL. NO utilice las muestras de código como se presentan aquí, sin asegurarse de que cualquier entrada externa esté desinfectada.

$ids = join("','",$galleries);   
$sql = "SELECT * FROM galleries WHERE id IN ('$ids')";
 278
Author: Flavius Stef,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-22 17:24:00

Uso de DOP:[1]

$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;
$statement = $pdo->prepare($select);
$statement->execute($ids);

Uso de MySQLi [2]

$in = join(',', array_fill(0, count($ids), '?'));
$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;
$statement = $mysqli->prepare($select);
$statement->bind_param(str_repeat('i', count($ids)), ...$ids);
$statement->execute();
$result = $statement->get_result();

Explicación:

Utilice el operador SQL IN() para comprobar si existe un valor en una lista dada.

En general se ve así: {[19]]}

expr IN (value,...)

Podemos construir una expresión para colocarla dentro de () desde nuestro array. Tenga en cuenta que debe haber al menos un valor dentro del paréntesis o MySQL devolverá un error; esto equivale a asegurarse de que nuestro la matriz de entrada tiene al menos un valor. Para ayudar a prevenir ataques de inyección SQL, primero genere un ? para cada elemento de entrada para crear una consulta parametrizada. Aquí asumo que el array que contiene sus ids se llama $ids:

$in = join(',', array_fill(0, count($ids), '?'));

$select = <<<SQL
    SELECT *
    FROM galleries
    WHERE id IN ($in);
SQL;

Dado un array de entrada de tres elementos $select se verá como:

SELECT *
FROM galleries
WHERE id IN (?, ?, ?)

Nuevamente tenga en cuenta que hay un ? para cada elemento en la matriz de entrada. Luego usaremos PDO o MySQLi para preparar y ejecutar la consulta como se indica arriba.

Usando el operador IN() con cadenas

Es fácil cambiar entre cadenas e enteros debido a los parámetros enlazados. Para PDO no se requiere ningún cambio; para MySQLi cambie str_repeat('i', a str_repeat('s', si necesita verificar cadenas.

[1]: He omitido alguna comprobación de errores para la brevedad. Debe verificar los errores habituales para cada método de base de datos (o configurar su controlador de base de datos para lanzar excepciones).

[2]: Requiere PHP 5.6 o superior. Una vez más he omitido algunas comprobaciones de error para la brevedad.

 281
Author: Levi Morrison,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-15 20:58:40

Ints:

$query = "SELECT * FROM `$table` WHERE `$column` IN(".implode(',',$array).")";

Cadenas:

$query = "SELECT * FROM `$table` WHERE `$column` IN('".implode("','",$array)."')";
 48
Author: user542568,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-19 13:30:53

Suponiendo que desinfecte correctamente sus entradas de antemano...

$matches = implode(',', $galleries);

Luego simplemente ajuste su consulta:

SELECT *
FROM galleries
WHERE id IN ( $matches ) 

Cita valores apropiadamente dependiendo de su conjunto de datos.

 26
Author: AvatarKava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-05-25 19:38:46

Uso:

select id from galleries where id in (1, 2, 5);

Un bucle simple for each funcionará.

La forma de Flavius/AvatarKava es mejor, pero asegúrese de que ninguno de los valores del array contenga comas.

 10
Author: Matthew Flaschen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:32

Como Respuesta de Flavius Stef , puede usar intval() para asegurarse de que todos id son valores int:

$ids = join(',', array_map('intval', $galleries));  
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
 8
Author: Van-Duyet Le,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 11:55:07

Para MySQLi con una función de escape:

$ids = array_map(function($a) use($mysqli) { 
    return is_string($a) ? "'".$mysqli->real_escape_string($a)."'" : $a;
  }, $ids);
$ids = join(',', $ids);  
$result = $mysqli->query("SELECT * FROM galleries WHERE id IN ($ids)");

Para la DOP con declaración preparada:

$qmarks = implode(',', array_fill(0, count($ids), '?'));
$sth = $dbh->prepare("SELECT * FROM galleries WHERE id IN ($qmarks)");
$sth->execute($ids);
 7
Author: artoodetoo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-08 09:28:26

Debemos cuidar de Inyección SQL vulnerabilidades y una condición vacía . Voy a manejar ambos como abajo.

Para una matriz numérica pura, use la conversión de tipo apropiada viz intval o floatval o doubleval sobre cada elemento. Para tipos de cadenas mysqli_real_escape_string() que también se puede aplicar a los valores numéricos si lo desea. MySQL permite números así como variantes de fecha como cadena.

Para escapar apropiadamente los valores anteriores pasando a la consulta, cree una función similar a:

function escape($string)
{
    // Assuming $db is a link identifier returned by mysqli_connect() or mysqli_init()
    return mysqli_real_escape_string($db, $string);
}

Tal función probablemente ya esté disponible para usted en su aplicación, o tal vez ya haya creado una.

Desinfecta la matriz de cadenas como:

$values = array_map('escape', $gallaries);

Una matriz numérica se puede desinfectar usando intval o floatval o doubleval en su lugar como adecuado:

$values = array_map('intval', $gallaries);

Luego, finalmente, construye la condición de consulta

$where  = count($values) ? "`id` = '" . implode("' OR `id` = '", $values) . "'" : 0;

O

$where  = count($values) ? "`id` IN ('" . implode("', '", $values) . "')" : 0;

Dado que el array también puede estar vacío a veces, como $galleries = array();, debemos tener en cuenta que IN () no permite una lista vacía. También se puede usar OR en su lugar, pero el problema permanece. Así que la comprobación anterior, count($values), es para asegurar lo mismo.

Y añádelo a la consulta final:

$query  = 'SELECT * FROM `galleries` WHERE ' . $where;

TIP: Si desea mostrar todos los registros (sin filtrado) en caso de una matriz vacía en lugar de ocultar todas las filas, simplemente reemplace 0 con 1 en la parte falsa del ternario.

 6
Author: Izhar Aazmi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-18 20:05:31

Más seguro.

$galleries = array(1,2,5);
array_walk($galleries , 'intval');
$ids = implode(',', $galleries);
$sql = "SELECT * FROM galleries WHERE id IN ($ids)";
 5
Author: Filipe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-13 15:41:31

Podemos usar esta cláusula "WHERE id IN" si filtramos la matriz de entrada correctamente. Algo como esto:

$galleries = array();

foreach ($_REQUEST['gallery_id'] as $key => $val) {
    $galleries[$key] = filter_var($val, FILTER_SANITIZE_NUMBER_INT);
}

Como el siguiente ejemplo: introduzca la descripción de la imagen aquí

$galleryIds = implode(',', $galleries);

Es decir, ahora debe usar $query = "SELECT * FROM galleries WHERE id IN ({$galleryIds})";

 5
Author: Supratim Roy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-15 17:15:52

La biblioteca de

Col.Shrapnel SafeMySQL para PHP proporciona marcadores de posición con sugerencias de tipo en sus consultas parametrizadas, e incluye un par de marcadores de posición convenientes para trabajar con matrices. El marcador de posición ?a expande un array a una lista separada por comas de cadenas escapadas*.

Por ejemplo:

$someArray = [1, 2, 5];
$galleries = $db->getAll("SELECT * FROM galleries WHERE id IN (?a)", $someArray);

* Tenga en cuenta que, dado que MySQL realiza coerción automática de tipos, no importa que SafeMySQL convierta los ID anteriores en cadenas, aún obtendrá la correcta resultado.

 4
Author: Mark Amery,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-05-17 19:03:03

Usted puede tener tabla texts (T_ID (int), T_TEXT (text)) y cuadro test (id (int), var (varchar(255)))

En insert into test values (1, '1,2,3') ; las siguientes filas de salida de los textos de la tabla donde T_ID IN (1,2,3):

SELECT * FROM `texts` WHERE (SELECT FIND_IN_SET( T_ID, ( SELECT var FROM test WHERE id =1 ) ) AS tm) >0

De esta manera puede gestionar una simple relación de base de datos n2m sin una tabla adicional y utilizando solo SQL sin la necesidad de usar PHP u otro lenguaje de programación.

 4
Author: SERJOU,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-18 19:46:24

Debido a que la pregunta original se refiere a una matriz de números y estoy usando una matriz de cadenas, no pude hacer que los ejemplos dados funcionaran.

Encontré que cada cadena necesitaba ser encapsulada en comillas simples para trabajar con la función IN().

Aquí está mi solución

foreach($status as $status_a) {
        $status_sql[] = '\''.$status_a.'\'';
    }
    $status = implode(',',$status_sql);

$sql = mysql_query("SELECT * FROM table WHERE id IN ($status)");

Como puede ver, la primera función envuelve cada variable de matriz en single quotes (\') y luego implosiona la matriz.

NOTA: $status no tiene comillas simples en la instrucción SQL.

Hay probablemente una mejor manera de añadir las comillas, pero esto funciona.

 2
Author: RJaus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-08-04 14:34:10

Además de usar la consulta IN, tiene dos opciones para hacerlo, ya que en una consulta IN existe el riesgo de una vulnerabilidad de inyección SQL. Puede usar looping para obtener los datos exactos que desea o puede usar la consulta con O case

1. SELECT *
      FROM galleries WHERE id=1 or id=2 or id=5;


2. $ids = array(1, 2, 5);
   foreach ($ids as $id) {
      $data[] = SELECT *
                    FROM galleries WHERE id= $id;
   }
 2
Author: Gaurav Singh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-18 19:49:48

Más un ejemplo:

$galleryIds = [1, '2', 'Vitruvian Man'];
$ids = array_filter($galleryIds, function($n){return (is_numeric($n));});
$ids = implode(', ', $ids);

$sql = "SELECT * FROM galleries WHERE id IN ({$ids})";
// output: 'SELECT * FROM galleries WHERE id IN (1, 2)'

$statement = $pdo->prepare($sql);
$statement->execute();
 2
Author: Ricardo Canelas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-19 10:45:30

A continuación se muestra el método que he utilizado, utilizando PDO con marcadores de posición con nombre para otros datos. Para superar la inyección SQL estoy filtrando la matriz para aceptar solo los valores que son enteros y rechazando todos los demás.

$owner_id = 123;
$galleries = array(1,2,5,'abc');

$good_galleries = array_filter($chapter_arr, 'is_numeric');

$sql = "SELECT * FROM galleries WHERE owner=:OWNER_ID AND id IN ($good_galleries)";
$stmt = $dbh->prepare($sql);
$stmt->execute(array(
    "OWNER_ID" => $owner_id,
));

$data = $stmt->fetchAll(PDO::FETCH_ASSOC);
 0
Author: kojow7,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-24 16:31:28

Camino seguro sin DOP:

$ids = array_filter(array_unique(array_map('intval', (array)$ids)));

if ($ids) {
    $query = 'SELECT * FROM `galleries` WHERE `id` IN ('.implode(',', $ids).');';
}
  • (array)$ids Cast $ids variable a array
  • array_map Transformar todos los valores de matriz en enteros
  • array_unique Eliminar valores repetidos
  • array_filter Eliminar valores cero
  • implode Unir todos los valores en la selección
 0
Author: Lito,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-30 09:12:17

Los métodos básicos para prevenir la inyección SQL son:

  • Utilice instrucciones preparadas y consultas parametrizadas
  • Escapar de los caracteres especiales en su variable insegura

Usando instrucciones preparadas y consultas parametrizadas la consulta se considera la mejor práctica, pero si elige el método de caracteres de escape, puede probar mi ejemplo a continuación.

Puede generar las consultas usando array_map para agregar una comilla simple a cada uno de los elementos del $galleries:

$galleries = array(1,2,5);

$galleries_str = implode(', ',
                     array_map(function(&$item){
                                   return "'" .mysql_real_escape_string($item) . "'";
                               }, $galleries));

$sql = "SELECT * FROM gallery WHERE id IN (" . $galleries_str . ");";

El var sql sql generado será:

SELECT * FROM gallery WHERE id IN ('1', '2', '5');

Nota: mysql_real_escape_string, como se describe en su documentación aquí, fue obsoleta en PHP 5.5.0, y fue eliminada en PHP 7.0.0. En su lugar, se debe usar la extensión MySQLi o PDO_MySQL. Consulte también MySQL: elegir una guía de API y preguntas frecuentes relacionadas para obtener más información. Las alternativas a esta función incluyen:

  • Mysqli_real_escape_string()

  • DOP:: quote()

 -2
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-03-26 08:48:07