Tengo un caso en el que estoy importando una hoja de cálculo de elementos, y al insertar necesito verificar cada elemento si ya existe (ya sea por serial_no o serial_imei) y luego para cada uno que EXISTE necesito informar al usuario cuando se realiza el envío con un mensaje como: "El artículo con número de serie 123456 ya se encontró en la base de datos".
Aquí está la forma en que estoy insertando:
$stmt = $db->prepare("INSERT INTO devices (serial_imei,serial_no) VALUES (?,?)"); for ($i = 0; $i < $min; $i++) { $stmt->bind_param("ii", $imei[$keysTwo[$i]], $serial_no[$keysOne[$i]]); $stmt->execute(); }Vi en alguna parte que puedo usar INSERT IGNORE, pero ¿cómo puedo hacer eso dentro del ciclo y devolver un mensaje de advertencia para cada elemento que se haya encontrado?
Suponiendo que tiene una clave ÚNICA compuesta tanto en serial_imei como en serial_no , puede detectar la excepción, verificar si el código de error de MySQL es 1062 (entrada duplicada) y recopilar estas filas en una tabla. A continuación, puede mostrar la tabla al usuario para informarle cuáles ya existían.
Déjame mostrarte esto con un ejemplo del siguiente código:
$imei = [1111, 2222]; $serial_no = [3333, 4444]; $min = 2; // We will collect all duplicate keys to be displayed later $duplicates = []; $stmt = $mysqli->prepare("INSERT INTO devices (serial_imei,serial_no) VALUES (?,?)"); for ($i = 0; $i < $min; $i++) { $stmt->bind_param('ss', $imei[$i], $serial_no[$i]); // execute() is wrapped in try-catch to catch the exception from MySQL try { $stmt->execute(); } catch (\mysqli_sql_exception $e) { // We are only interested in 1062 (duplicate entry) and we want to rethrow anything else if ($e->getCode() !== 1062) { // If not 1062 then rethrow throw $e; } $duplicates[] = ['imei' => $imei[$i], 'no' => $serial_no[$i]]; } } foreach ($duplicates as $dup) { echo "Duplicate! IMEI:{$dup['imei']} Serial No.:{$dup['no']} ".PHP_EOL; }Si, por algún motivo, las columnas no tienen una restricción ÚNICA, debe ejecutar una instrucción SELECT paralela para ver si la fila existe antes de insertarla. Esto es un poco más complicado y probablemente también más lento. Si hace esto, primero debe adquirir un bloqueo en la tabla para asegurarse de que ningún otro proceso inserte filas duplicadas al mismo tiempo.
$duplicates = []; $mysqli->autocommit(0); $mysqli->query('LOCK TABLES devices WRITE'); // SELECT stmt $select_stmt = $mysqli->prepare("SELECT COUNT(1) FROM devices WHERE serial_imei=? AND serial_no=?"); // INSERT stmt $stmt = $mysqli->prepare("INSERT INTO devices (serial_imei,serial_no) VALUES (?,?)"); for ($i = 0; $i < $min; $i++) { // First execute SELECT to check if the value exists already $select_stmt->bind_param('ss', $imei[$i], $serial_no[$i]); $select_stmt->execute(); $exists = $select_stmt->get_result()->fetch_row()[0]; if ($exists) { $duplicates[] = ['imei' => $imei[$i], 'no' => $serial_no[$i]]; } else { // No result was found in DB, let's insert $stmt->bind_param('ss', $imei[$i], $serial_no[$i]); $stmt->execute(); } } $mysqli->autocommit(1); $mysqli->query('UNLOCK TABLES');