问题
I have a case where I am importing a spreadsheet of items, and when inserting I need to check for each item if already exists (either by serial_no or serial_imei) and then for each that EXISTS I need to inform the user when the submission is done with a message such as: "Item with serial no 123456 was already found in database".
Here is the way I am inserting:
$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();
}
I saw somewhere that I can use INSERT IGNORE but how can I do that inside loop and return a warning message for each item that has been found?
回答1:
Assuming that you have a composite UNIQUE key on both serial_imei
and serial_no
you can catch the exception, check if the MySQL error code is 1062 (duplicate entry) and collect this rows into a table. You can then display the table to the user to inform which ones were already existing.
Let me show you this with an example of the following code:
$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;
}
If for some reason the columns do not have UNIQUE constraint then you need to execute a parallel SELECT statement to see if the row exists prior to inserting it. This is slightly more complicated and probably also slower. If you do this, then you must first acquire a lock on the table to make sure no other process inserts duplicate rows at the same time.
$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');
来源:https://stackoverflow.com/questions/62941220/how-to-check-if-element-exists-in-database-and-return-a-warning-message