mysql insert ignore, replace or update on duplicate - did insert? - php

I am using php to 'insert ignore' a row into my database. Is there a way to find out whether a row was inserted?
the code looks like this:
if($stmt = $mysqli->prepare('INSERT IGNORE INTO my_table (key_a, key_b) VALUES (?, ?)'))
{
$stmt->bind_param('ss', 'hello', 'world');
$stmt->execute();
$stmt->close();
}
Thank you guys!

Try like this:
if($stmt->execute())
{
echo "Success";
}
else
{
echo "Error";
}
Also check mysqli::$affected_rows
$mysqli->affected_rows
mysqli::$affected_rows -- mysqli_affected_rows — Gets the number of
affected rows in a previous MySQL operation

Try the following: $mysqli->affected_rows
Link:
/* update rows */
$mysqli->query("UPDATE Language SET Status=1 WHERE Percentage > 50");
printf("Affected rows (UPDATE): %d\n", $mysqli->affected_rows);

MySQL has ON DUPLICATE KEY feature where you can define what to do if your insert fails because of some constrains like unique_key or primary_key being inserted twice.
On that cases, cases, you can trap such errors.
If the query inserts normally, it won't execute this block.
If the query fails, the block will be executed.
Now, you may tweak this feature.
For example, in your table, add one insert_attempts columns with default 0 (zero) value.
And try to execute:
INSERT INTO my_table (key_a, key_b)
VALUES (?, ?)
ON DUPLICATE KEY UPDATE
insert_attempts = insert_attempts+1
;
After all records are successful; SELECT the rows with insert_attempt > 0.

I think the execute() method will return a true or false, so I would suggest more sth. like this (also note that u need to do this before you close the connection):
if ($stmt->execute()) {
echo "success"
}
else
{
echo "Error"
}
, also consider to fetch the statement to see how many lines were affected. You can do that with mysqli_stmt_affected_rows(statement), it will give you the lines affected. If you use it, it couls look like this:
int mysqli_stmt_affected_rows ( mysqli_stmt $stmt )
also read here.

Related

SQL INSERT INTO table results in duplicates

I have a script that I have setup a CRON for that is getting values from a 3rd party server via JSON (cURL)
Right now every time the cron runs it will INSERT a completely new record. Causing duplicates, and resulting me in manually removing the dups.
How would I go about preventing duplicates, and only update the information that is either missing, or different from the NEW $VAR values?
What I want to do can be expressed like this: IF old value is NOT new value use new value else use old value;
if ($stmt->num_rows !== 1) {
if ($insert_stmt = $mysqli->prepare("
INSERT INTO members (
start_date
)
VALUES (?)"))
{
$insert_stmt->bind_param('s',
$StartDate,
);
if (! $insert_stmt->execute()) { echo ''; }
}
}
}
You should try using INSERT ... ON DUPLICATE KEY UPDATE. Documentation
This does mean that you will have to define some unique (could be primary) key to the table that is always constant so MySQL knows what to update.
A quick example of how you would do it:
INSERT INTO table (f1,f2,f3) VALUES ('something_unique',2,5)
ON DUPLICATE KEY UPDATE f2=2,f3=5
The following statement will be silently ignored if one of the fields with the flags UNIQUE or PRIMARY KEY already exist in the database. If you're searching for INSERT IF NOT EXISTS this is probably what you're looking for:
INSERT IGNORE INTO `members` SET name='Steve',start_date='2015-11-20';
You can also overwrite a record that already exists using REPLACE. If it doesn't yet exist, it will be created:
REPLACE INTO `members` SET name='Steve',start_date='2015-11-20';
Another thing to consider would be INSERT ... ON DUPLICATE KEY UPDATE syntax:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;
I ended up writing another if statement to check if a unique value existed from incoming and the existing db value existed and leaving it blank to prevent it from importing duplicates. I also wrote a separate file to update where values differentiate between what I am receiving as (new) and what is in the database (old) which actually worked out great for my application.
Here is my answer for anyone else that runs into this issue :)
$prep_stmt = "SELECT * FROM table WHERE column_keys=?";
$stmt = $mysqli->prepare($prep_stmt);
if ($stmt) {
$stmt->bind_param('s',$varvalues);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
if ($insert_stmt = $mysqli->prepare("")) {
$insert_stmt->bind_param('');
if (! $insert_stmt->execute()) {
echo 'shits broke'; }
}
}
else { if ($insert_stmt = $mysqli->prepare("
INSERT INTO table (column_keys)
VALUES (?)")) // you will need a ? per column seperate by a , (?,?,?...?)
{ $insert_stmt->bind_param('s',
$varvalues
); // you will also need to bind a 's' (string) 'i' for num, etc per $var value.
if (! $insert_stmt->execute()) { echo 'shits broke';} //lol
}
}
}
Also a simple error reporting trick I stumbled upon that helped me clean up a few things I overlooked. Just place it at the top of the file, or above you want to debug ;)
error_reporting(E_ALL);

Can While Loop be used for Error Catching?

I am using try catch algorithm when inserting a record to a MySQL table. My scripting language is PHP.
try {
/*
UDID generation algo goes here.
*/
$sql = "INSERT INTO tablex (udid, name)
VALUES ('$udid', 'Doe')";
$conn->exec($sql);
echo "New record created";
}
catch(PDOException $e)
{
echo "Error"
}
$conn = null;
How do I re-write the above so that instead of try catch, I use a loop. If there is an error, try again. Break out of the loop if there is no error.
There is "While True" but I don't know if the "Try Catch" should be part of the While True loop..
The purpose of this is to save a UDID - the unique value is set in MYSQL. If I generate the same value, I may get the error. Hence, why the loop.
I feel like you're going about this the wrong way. Instead of trying to insert a value that might not be unique, I would try to see if that value exists first. You could perform a query such as
do {
//$udid = create uuid
$query = "SELECT COUNT(*) FROM tablex WHERE udid = :udid";
$statement = $pdo->prepare($query);
$statement->bindValue("udid", $udid);
$result = $statement->fetchAll();
} while ($result["count"] === 1);
//insert row into table
This is just off the top of my head and it can be refactored even better. You could also leverage your database to generate the UDID for you if you prefer. You could run a query to get all of the udid's from your table and just run in_array to check to see if the value is there, then you're only hitting your database twice. Anyway, you really don't want to try to abuse a try catch like that.
mysql has a function for something like this you would add an "ON DUPLICATE KEY UPDATE" to your insert statement
Example:
INSERT INTO table(x, y, z) values (?, ?, ?) ON DUPLICATE KEY UPDATE x=?;
Also see this link for more info:
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

PHP MySQL PDO duplicates

I have the below code, which works perfect. What i want to do is to check the refNo first to see if there are duplicates entries in MySQL. If there is then appear a warning message, otherwise appear a "ok" message. How can i do that with PDO? Any help?
(include("db.php"));
$SQLquery = "INSERT INTO mydatabase (refNo, name)
VALUES ('".$_POST["refNo"]."', '".$_POST["name"]."');";
$STH = $dbc->query($SQLquery);
?>
edit: Hello guys,
i prefer not to add primary keys. Is there any other way?
Set up refNo as a primary key. You could also create it as unique but that defeats the purpose - your reference number appears to be a unique primary identifier. Perfect choice for a primary key.
Further, change your query
try {
$SQLquery = "INSERT INTO mydatabase (refNo, name) VALUES (:refNo, :name)";
$SQLquery = $dbc->prepare($SQLquery);
$SQLquery->bindValue(':refNo', $_POST['refNo']);
$SQLquery->bindValue(':name', $_POST['name']);
$SQLquery->execute();
} catch (Exception $e) {
die("Insert error");
}
$count = $SQLquery->rowCount();
if ($count == 1) {
echo "Record added!";
}
This binds the post value to prevent SQL injection too.
Edit: You could follow this up with $count = $SQLquery->rowCount(); which will be 1 if the insert was successful, as it appears you've edited your question since you posted it for more info.
If you want to do this without using a database level constraint, you'll need to do an extra SELECT statement before inserting into the table. But that gives you no absolute guarantees, as it might be two processes want to insert the same row at the same time and they will still succeed.
-- it'll look a little something like this; I'm not familiar with PDO but the structure should be the same
$selectQuery = "SELECT * FROM mydatabase
WHERE refno = '".$_POST["refNo"]."'";
$res = $dbc->query( $selectQuery );
if( $res->count() > 0 ) {
// this result already exists; show error
}
else {
// this result is new; put the insert query here
}

How to determine if MySQL UPDATE actually matched any rows with WHERE clause?

I want to run an update like such in PHP
// pseudocode
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
IF AFFECTED_ROWS == 1 THEN
UPDATE invoice_item SET price=? WHERE invoice_id=?
For added security, I appended creater_id to ensure that the code only updates if the logged in user is the invoice creator, otherwise, the system will not update.
I originally intended to check this condition using AFFECTED_ROWS. But eventually after much frustration, I realise AFFECTED_ROWS return 0 if all the new values are the same as the old values. This means that even if I have different values for the invoice_item, they will not be updated.
Other than doing a SELECT before the UPDATE, is there SQL query or PHP functions that will tell me if the UPDATE matched any row, so that I can proceeed to UPDATE invoice_item accordingly?
You can use ROW_COUNT() and if you read that it explains that when connecting to the DB you can specify the CLIENT_FOUND_ROWS flag which will give the number of rows found for the update, regardless of if they have the same value of what you're updating with.
Hope this helps.
I've taken this from my code so things like $link need to be in place- but it shows what you are interested in
function update() {
$q = "UPDATE table SET field1=? WHERE field2 = $value";
/* create a prepared statement */
$stmt = mysqli_stmt_init($link);
if (mysqli_stmt_prepare($stmt, $q)) {
mysqli_stmt_bind_param($stmt, "s", $field1);
mysqli_stmt_execute($stmt);
if(mysqli_stmt_errno($stmt)){
echo("Sql Error: ".$q. ' Sql error #: '.mysqli_stmt_errno($stmt). ' - ' . mysqli_stmt_error($stmt);
return false;
}
else{
$numrows = mysqli_stmt_affected_rows($stmt);
if (mysqli_stmt_errno($stmt) == 0 || mysqli_stmt_errno($stmt) ==''){
// numrows = -1 is flag no error and no rows affected
$numrows = ($numrows ==0?-1:$numrows);
}
else{
echo("Sql Error: ".$q. ' Sql error #: '.mysqli_stmt_errno($stmt). ' - ' . mysqli_stmt_error($stmt);
return false;
}
/* close statement */
mysqli_stmt_close($stmt);
return $numrows;
}
}
}
As per documentation on ROW_COUNT():
ROW_COUNT() returns the number of rows changed, deleted, or inserted by the last statement if it was an UPDATE, DELETE, or INSERT. For other statements, the value may not be meaningful.
Your query:
Other than doing a SELECT before the UPDATE, is there SQL query or PHP functions that will tell me if the UPDATE matched any row
You can also use ROW_COUNT() within an UPDATE or any other DDL or DML statement.
Example: Using your pseudocode:
// pseudocode
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
IF ( ROW_COUNT() >= 1 ) THEN
UPDATE invoice_item SET price=? WHERE invoice_id=?
END IF;
Or else, you can try like:
UPDATE invoice SET due_date=? WHERE invoice_id=? AND creater_id=?;
UPDATE invoice_item SET price=
(case when ( row_count() >= 1 ) then ? else price end)
WHERE invoice_id=?;
Before setting the parameter value check again for the row_count() value to decide whether to set values for 1 or more parameters.
You can take this back to 1 query and not worry about affected rows:
UPDATE
invoice
left join invoice_item on invoice_item.invoice_id = invoice.invoice_id
SET
invoice.due_date = ?, -- the WHERE will only let this happen if it will be changed
invoice_item.price = ? -- the WHERE will only let this happen if it will be changed
WHERE
invoice.invoice_id = ?
and invoice.creater_id = ?
and invoice.due_date != ? -- here compare the new due_date to the one already in the db

Fetch number of affected rows and last inserted ID using PDO statement

How can I display the numbers of affected rows in this:
$sql = $conn->prepare ("UPDATE countries SET country=:country");
$sql->bindValue(":country", "blablaa");
$sql->execute();
And how can I show the last inserted ID with this:
$sql = $conn->prepare ("INSERT INTO countries (country) VALUES (:country)");
$sql->bindValue(":country", "test");
$sql->execute();
echo $sql->lastInsertId(); // id of last inserted
I tried, but am receiving an error call to undefined method PDO::lastInsertId()
I think this can help you:
PDOStatement::rowCount()
returns the number of rows affected by the last DELETE, INSERT, or UPDATE statement executed by the corresponding PDOStatement object.
http://php.net/manual/en/pdostatement.rowcount.php
$sql->lastInsertId();
Needs to be replaced with
$dbh->lastInsertId();
Where $dbh is your PDO object.
See here for more information.
exec returns the number of affected rows, execute only returns a true or false value.

Categories