MySQL with PHP, trying to update a row:
$dbQuery = 'UPDATE UserTable SET Age=25 WHERE Id=3';
$result = mysqli_query($dbLink, $dbQuery);
if ($result === FALSE) {
// Take care of error
}
else {
$numAffectedRows = mysqli_affected_rows($dbLink);
}
I get zero $numAffectedRows in two different cases:
1. When there is no user row with Id=3
2. When there is a user row with Id=3 but Age was already 25 before
Is there a way I can distinguish between the two cases? (apart from reading the row before and manually check the value before updating)
According to mysql documentation, you can change the behaviour of affected_rows by passing the MYSQLI_CLIENT_FOUND_ROWS flags while connecting using mysql_real_connect.
In this case, mysql_affected_rows returns the number of rows matched by the WHERE condition, not the number of updated rows.
I don't think this is possible with just one query.
I would go for INSERT INTO..ON DUPLICATE approach.
$dbQuery = "INSERT INTO UserTable (Id,Age) VALUES('3','25') ON DUPLICATE KEY
UPDATE Id='3',Age='25'";
$result = mysql_query($dbQuery);
if ($result === FALSE) {
// Take care of error
}
else {
$numAffectedRows = mysql_affected_rows();
// $numAffectedRows = 0 => row exist
// $numAffectedRows = >0 => row added with Id,Age specified
}
Related
When I'm updating MySQL records using the following SQL code, the result is always the same - it always update ALL records with the same value.
I used print_r($_POST); and found that the correct values were passed in PHP form.
// create and execute UPDATE query
foreach($_POST['update_category'] as $number => $update_category) {
$query = "UPDATE goals SET category='$update_category',goal='".$_POST['update_goal'][$number]."' WHERE username='$username';";
mysql_query($query, $connection);
}
I have updated my records based on specific condition after that I want to know the ids from the affected rows.
$sql = mysqli_query("update table set xxx='".$x."' where yyy='".$y."'");
Now after executing this query I want to know the affected rows.
Simple yet effective
$last_id = mysqli_insert_id($conn);
http://www.w3schools.com/php/php_mysql_insert_lastid.asp
You must first fetch the IDs, and then perform the update. If concurrency is a concern, you can use a locking read (provided that your table is stored in a transactional engine, such as InnoDB):
$mysqli->autocommit(FALSE);
$select = $mysqli->prepare('SELECT id FROM table WHERE yyy = ? FOR UPDATE');
$select->bind_param('s', $y);
$select->execute();
$update = $mysqli->prepare('UPDATE table SET xxx = ? WHERE yyy = ?');
$update->bind_param('ss', $x, $y);
$update->execute();
$mysqli->commit();
// here are the IDs that were updated
$select->bind_result($id);
while ($select->fetch()) printf('Updated id: %s\n', $id);
The only way I can think of is to first sleect rows that would be updated with the update statement, those are:
$updatableIds = mysqli_query("SELECT id FROM table WHERE xxx !='".$x."' AND yyy='".$y."'");
we add xxx !='".$x."' because if value of xxx already was $x those rows would not be affected.
Next you run the update
$sql = mysqli_query("update table set xxx='".$x."' where yyy='".$y."'");
UPDATE users
SET type = '3'
WHERE type = '2';
To find out the last affected row right after the statement, it should be slightly updated as follows:
UPDATE users
SET type = '3',
user_id=LAST_INSERT_ID(user_id)
WHERE type = '2';
// use function
function updateAndGetId($value)
{
$query ="UPDATE users
SET type = '$value',
user_id=LAST_INSERT_ID(user_id)
WHERE type = '2'";
mysql_query($query)
return mysql_insert_id();
}
$lastUpdatedRow = updateAndGetId(3);
In case you want to update only really changed row, add a conditional update of the user_id through the LAST_INSERT_ID and check if the data is going to change in the row.
I have a simple MYSQL query:
INSERT INTO table (col1,col2) VALUES ('1','2')
ON DUPLICATE KEY UPDATE col1 = '1', col2 = '2'
I use PHP PDO statements to query the database. Is there a way to know if the query executed resulted into a new inserted row or an existing was updated?
One way to do so is to get the number of rows before executing the query, then get the number of rows after executing the query, if they're not equal, it means a new row was inserted and if they are equal, it means a row was updated.
$sql = "SHOW TABLE STATUS LIKE 'TABLE_NAME'";
$stmt = $pdo->prepare($sql);
$stmt->execute();
$row = $stmt->fetch();
$number_of_rows_before = $row['Rows'];
// Do your query here, afterwards
$stmt = $pdo->prepare($sql);
$stmt->execute();
$row = $stmt->fetch();
$number_of_rows_after = $row['Rows'];
// If condition
if($number_of_rows_before == $number_of_rows_after) // Update was executed
else // a new row was inserted.
Just use mysqli_affected_rows,it returns the number of rows affected by the last INSERT, UPDATE, REPLACE or DELETE query.
From PHP documentation:
In the case of "INSERT ... ON DUPLICATE KEY UPDATE" queries, the return value will be 1 if an insert was performed, or 2 for an update of an existing row.
see https://www.php.net/manual/en/function.mysql-affected-rows.php
From Mysql manual:
"With ON DUPLICATE KEY UPDATE, the affected-rows value per row is 1 if
the row is inserted as a new row and 2 if an existing row is updated."
See: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
This is the most reliable way to do it.
maybe you put the answer right into the query like:
INSERT INTO table (col1,col2, col_type) VALUES ('1','2','inserted')
ON DUPLICATE KEY UPDATE col1 = '1', col2 = '2', col_type = 'updated'
I have a table with a lot of columns. I have a function that duplicates my record into a new row with an updated auto-incremented ID.
The function works perfectly however, on some of my INT columns, sometimes I have a NULL as the default. When the record is duplicated, it turns my NULL placement into a 0.
I'm assuming it's because I am doing '" . value . "'
Could anyone help me figure out how I could make NULL values be inserted as " . NULL . " and keep my other values as '" . value . "'?
EDIT I'm having trouble differentiating a null and a blank value. I've tried empty() and is_null() and a varchar with no value and an INT with a NULL value isn't showing a difference
note: I understand that I am using an outdated mysql extension. For right now, I'm just trying to process my null variables correctly.
function duplicateRow($table, $id_field, $id_value)
{
// copy content of the record you wish to clone
$entity = mysql_fetch_array(mysql_query("SELECT * FROM {$table} WHERE {$id_field}={$id_value}"), MYSQL_ASSOC) or die("Could not select original record");
// set the auto-incremented id's value to blank. If you forget this step, nothing will work because we can't have two records with the same id
$entity[$id_field] = "";
// insert cloned copy of the original record
mysql_query("INSERT INTO {$table} (".implode(", ",array_keys($entity)).") VALUES ('".implode("', '",array_values($entity))."')") or die(mysql_error());
//returns the new id
return mysql_insert_id();
}
You don't need to fetch the data into PHP only then to send it back to MySQL: INSERT ... SELECT is a single SQL command that enables the whole shebang to take place natively within the database.
However, you need to exclude the $id_field from the operation, so you can't use the * wildcard but must instead explicitly list the column names. This adds some complexity, especially to perform the operation in a safe, injection-proof way:
function duplicateRow($table, $id_field, $id_value)
{
// prevent SQL injection
$enc_map = array(
'utf8' => 'UTF-8',
'latin1' => 'Windows-1252' // etc.
);
mb_regex_encoding($enc_map[mysql_client_encoding()]);
$table_safe = '`'.mb_ereg_replace('`', '``', $table ).'`';
$id_field_safe = '`'.mb_ereg_replace('`', '``', $id_field).'`';
$id_value_safe = mysql_real_escape_string($id_value);
// fetch column names
$fields = array();
$qry = mysql_query("SHOW COLUMNS FROM $table_safe");
while ($row = mysql_fetch_assoc($qry))
if ($row['field'] != $id_field)
$fields[] = '`'.mb_ereg_replace('`', '``', $row['field']).'`';
$fields_safe = implode(',', $fields);
// duplicate the record
mysql_query("
INSERT INTO $table_safe
($fields_safe)
SELECT $fields_safe
FROM $table_safe
WHERE $id_field_safe = '$id_value_safe'
");
//returns the new id
return mysql_insert_id();
}
Note that the ancient ext/mysql extension has been deprecated and its use in new code has been discouraged for years. You should seriously consider switching to either MySQLi or PDO.
What is your MySQL Version? some versions of MySQL (5.5 and earlier if I'm not mistaken) convert null values to empty for string fields and 0 to int fields.
You have to force null value or update to MySQL 5.6
I ended up making a foreach statement that checked to see if my value was null and changed the query a little bit. This may not be the greatest, the right, or practical way to do this but it works. If anyone has any suggestions, they are 100% appreciated!
The reason I kept my function mostly the same is I needed to use this for multiple large tables. So I didn't know exactly what the fields were going to be.
function duplicateRow($table, $id_field, $id_value)
{
// copy content of the record you wish to clone
$entity = mysql_fetch_array(mysql_query("SELECT * FROM {$table} WHERE {$id_field}={$id_value} AND snapshot=0"), MYSQL_ASSOC) or die("Could not select original record");
foreach ($entity as &$value) { if(is_null($value) == true) { $value = "NULL"; } else { $value = "'$value'"; } }
// set the auto-incremented id's value to blank. If you forget this step, nothing will work because we can't have two records with the same id
$entity[$id_field] = "'";
// insert cloned copy of the original record
$query = "INSERT INTO {$table} (".implode(", ",array_keys($entity)).") VALUES ('".implode(", ",array_values($entity)).")";
mysql_query($query) or die(mysql_error());
//returns the new id
return mysql_insert_id();
}
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