Error al preparar una consulta de inserción múltiple

8 minutos de lectura

avatar de usuario
Grifo

// BUILD VALUES
$count = count($matches);
for($i = 0; $i < $count; ++$i) {
    $values[] = '(?)';
}
// INSERT INTO DATABASE
$q = $this->dbc->prepare("INSERT INTO hashes (hash) VALUES " . implode(', ', $values) . " ON DUPLICATE KEY UPDATE hash = hash");
$q->execute($matches);

El código anterior falla con el siguiente error

SQLSTATE[HY093]: Número de parámetro no válido: el parámetro no se definió

Aunque cuando count($matches) == count($values) justo antes de ejecutar se llama?

¿Que esta pasando aqui?

  • ¿Has intentado pasar array_values($matches) en su lugar?

    – Jacobo

    10 de junio de 2012 a las 4:40

  • Por qué ON DUPLICATE KEY UPDATE hash = hash? También puede hacer INSERT IGNORE .... ¿Querías hacer UPDATE hash = VALUES(hash)?

    – eggyal

    10 de junio de 2012 a las 5:12

  • Hizo el $values array ya contiene algo antes del bucle? Además, ¿por qué no preparar una sola INSERT INTO hashes (hash) VALUES (?) y ejecutarlo varias veces?

    – eggyal

    10 de junio de 2012 a las 5:18

  • @eggyal Estoy insertando alrededor de 1000 valores y hacer una inserción múltiple es unas 10 veces más rápido 🙂

    – Grifo

    10 de junio de 2012 a las 16:09

  • @Griff: ¿Es eso cierto en el caso de ejecutar una declaración preparada varias veces? Nunca lo he comparado yo mismo, pero siempre había entendido que el impacto en el rendimiento era insignificante…

    – eggyal

    10 de junio de 2012 a las 21:45

avatar de usuario
Haroon

Este error que está recibiendo se debe a que la cantidad de elementos en $values & $matches no coincide.

Si $values & $matches no contienen la misma cantidad de elementos, entonces la inserción fallará, debido a que la consulta espera X parámetros pero está recibiendo Y datos $matches. En tu caso, $values probablemente ya contenga algunos valores, que es el motivo de la discrepancia de conteo. Para evitar eso, siempre debe inicializar una matriz antes del bucle.

Creo que también deberá asegurarse de que el hash de la columna también tenga un índice único.

$matches = array('1');
$count = count($matches);
$values = [];
for($i = 0; $i < $count; ++$i) {
    $values[] = '(?)';
}

// INSERT INTO DATABASE
$sql = "INSERT INTO hashes (hash) VALUES " . implode(', ', $values) . " ON DUPLICATE KEY UPDATE hash=values(hash)";
$stmt = $dbh->prepare($sql);
$data = $stmt->execute($matches);

  • Gran respuesta, me encontré con esto, porque definí dos columnas con el mismo identificador: :example¡ese también debería ser un punto a verificar!

    – Darren

    22 de junio de 2015 a las 3:12

  • Solo para agregar, podría deberse a que el parámetro que está tratando de vincular simplemente no existe …

    – Víctor H.

    3 de diciembre de 2015 a las 3:41

  • @Darren – Eres mi salvador en vivo. En mi llamada a bindParam que se ejecutó en un bucle foreach, había olvidado incluir la clave del índice de matriz, así que obtuve bindParam(‘:id’, ‘someValue’), bindParam(‘:id’, ‘someValue2’),… en lugar de bindParam(‘:id0’, ‘someValue’), bindParam(‘:id1’, ‘someValue’),… Espero que esto ayude a alguien a resolver su misterio

    – Erik Cerpnjak

    31 de mayo de 2016 a las 22:11


  • Creo que no entendiste la intención del OP. él estaba implosionando $count veces (?) -y no solo ?– con , porque algo como INSERT INTO hashes(hash) VALUES('What'),('Terrible'),('Failure'); funcionaría en SQL para hacer inserciones de 3 filas en una declaración. Tu respuesta sugiere algo como INSERT INTO hashes(hash) VALUES('What', 'Terrible' , 'Failure'); -hacer referencia a una columna y dar 3 valores para una fila! eso arrojaría Column count doesn't match value count error- ¿Cómo podría esto obtener +45 votos a favor y la aprobación de OP? (Claro: “Tendrás que adaptarlo un poco.” dijiste…)

    – Sebas SBM

    17 de septiembre de 2019 a las 9:31


  • @SebasSBM este fue exactamente mi pensamiento. Lo edité, para que sea al menos sensato. Entrando en mi colección de Stack Overflow WTF. Entonces votar es tal un misterio.

    – Tu sentido común

    30 de abril a las 6:24

avatar de usuario
danny f

SQLSTATE[HY093]: Número de parámetro no válido: el parámetro no se definió

Desafortunadamente, este error no es descriptivo para una variedad de problemas diferentes relacionados con el mismo problema: un error de vinculación. Tampoco especifica dónde está el error, por lo que su problema no está necesariamente en la ejecución, sino en la declaración sql que ya estaba ‘preparada’.

Estos son los posibles errores y sus soluciones:

  1. Hay una discrepancia de parámetros: el número de campos no coincide con los parámetros que se han vinculado. Cuidado con las matrices en matrices. Para verificar dos veces, use var_dump($var). “imprimir_r” no muestra necesariamente si el índice en una matriz es otra matriz (si la matriz tiene un valor), mientras que var_dump será.

  2. Ha intentado enlazar utilizando el mismo valor de enlace, por ejemplo: “:hash” y “:hash”. Cada índice tiene que ser único, incluso si lógicamente tiene sentido usar el mismo para dos partes diferentes, incluso si es el mismo valor. (es similar a una constante pero más como un marcador de posición)

  3. Si está vinculando más de un valor en una declaración (como suele ser el caso con un “INSERT”), debe vincular Param y luego vincular Valor a los parámetros. El proceso aquí es vincular los parámetros a los campos y luego vincular los valores a los parámetros.

     // Code snippet
     $column_names = array();
     $stmt->bindParam(':'.$i, $column_names[$i], $param_type);
     $stmt->bindValue(':'.$i, $values[$i], $param_type);
     $i++;
     //.....
    
  4. Cuando no es coherente al usar The backtick para delimitar literales que representan identificadores (no cadenas). (Usando “), pero una vez que los usa, debe ser consistente para esa consulta, es decir, no puede usar acentos graves para un identificador y no usarlos para otro, todos deben tener acentos graves si los usa. (por ejemplo, SELECCIONAR id DESDE my_table) No use back-ticks para marcadores de posición

  5. Cualquier valor entre comillas simples ” siempre se trata como un literal de cadena y no se leerá como un nombre de columna/tabla o marcador de posición para enlazar.

  • Gracias por tener la razón #2, me quedé estupefacto hasta que encontré esto aquí.

    usuario3277192

    10 de marzo de 2018 a las 1:24

  • Y tu versión inicial también estaba equivocada. Tú no poder vincular valores a column_names

    – Tu sentido común

    1 de mayo a las 14:36

  • En caso de que creas que puedes hacer algo como esto WHERE ` :column ` =1 , no funcionará. Observe el doble ” en el mensaje de error alrededor de id. PDO agrega comillas a los valores, haciendo que el nombre archivado sea literal 'id'. Lo que significa que no puede usar marcadores de posición para los nombres de las columnas. Los backticks no tienen absolutamente nada que ver con marcadores de posición y no se pueden usar con marcadores de posición de ninguna manera, ya sea como parte del nombre o como parte del entorno. Por favor, no difunda información engañosa.

    – Tu sentido común

    2 de mayo a las 4:25


  • no se donde lo conseguiste pero puedes usar backticks de manera inconsistente, donde quieras incluso para un solo nombre de columna. Además, todo este asunto del backtick no tiene absolutamente nada que ver con pregunta que está tratando de responder. La pregunta es sobre marcadores de posición, no acentos graves.

    – Tu sentido común

    2 de mayo a las 16:29


  • Y me acabo de dar cuenta, el #3 tampoco tiene sentido. Como ya aprendimos, no se puede vincular ningún nombre de columna, por lo que es difícil saber de qué está hablando. Y mucho menos, no existe tal problema que pueda resolverse entrelazando bindParam y bindValue. Puedes usar uno o ambos. Y tampoco causaría el error de número de parámetro no válido. Toda la declaración de “vincular los parámetros a los campos y luego vincular los valores a los parámetros” es una tontería clara como el cristal.

    – Tu sentido común

    2 de mayo a las 16:38


avatar de usuario
Ana

Tuve el mismo error después de usar el nombre de parámetro incorrecto al vincular.

darse cuenta :tokenHash en el VALUES cláusula de la consulta, pero :token_hash al atar.

Arreglar uno u otro resolvió el error.

// Prepare DB connection
$sql="INSERT INTO rememberedlogins (token_hash,user_id,expires_at)
        VALUES (:tokenHash,:user_id,:expires_at)";
$db = static::getDB();
$stmt = $db->prepare($sql);

// Bind values
$stmt->bindValue(':token_hash',$hashed_token,PDO::PARAM_STR);

El mismo error que encontré se mostrará si no coincide el nombre de la columna en PHP y el nombre de la columna de la base de datos. Compruébelo también. Esto es lo que tenía mal.

entiendo que la respuesta fue util sin embargo por alguna razon no me funciona sin embargo he movido la situacion con el siguiente codigo y esta perfecto

    <?php

$codigoarticulo = $_POST['codigoarticulo'];
$nombrearticulo = $_POST['nombrearticulo'];
$seccion        = $_POST['seccion'];
$precio         = $_POST['precio'];
$fecha          = $_POST['fecha'];
$importado      = $_POST['importado'];
$paisdeorigen   = $_POST['paisdeorigen'];
try {

  $server="mysql: host=localhost; dbname=usuarios";
  $user="root";
  $pass="";
  $base   = new PDO($server, $user, $pass);

  $base->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

  $base->query("SET character_set_results="utf8",
                     character_set_client="utf8",
                     character_set_connection = 'utf8',
                     character_set_database="utf8",
                     character_set_server="utf8"");

  $base->exec("SET character_set_results="utf8",
                     character_set_client="utf8",
                     character_set_connection = 'utf8',
                     character_set_database="utf8",
                     character_set_server="utf8"");

  $sql = "
  INSERT INTO productos
  (CÓDIGOARTÍCULO, NOMBREARTÍCULO, SECCIÓN, PRECIO, FECHA, IMPORTADO, PAÍSDEORIGEN)
  VALUES
  (:c_art, :n_art, :sec, :pre, :fecha_art, :import, :p_orig)";
// SE ejecuta la consulta ben prepare
  $result = $base->prepare($sql);
//  se pasan por parametros aqui
  $result->bindParam(':c_art', $codigoarticulo);
  $result->bindParam(':n_art', $nombrearticulo);
  $result->bindParam(':sec', $seccion);
  $result->bindParam(':pre', $precio);
  $result->bindParam(':fecha_art', $fecha);
  $result->bindParam(':import', $importado);
  $result->bindParam(':p_orig', $paisdeorigen);
  $result->execute();
  echo 'Articulo agregado';
} catch (Exception $e) {

  echo 'Error';
  echo $e->getMessage();
} finally {

}

?>

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad