Say I have this loop:
foreach ($array as $a) {
if ($a == $b) {
mysql_query("UPDATE table SET this = 'that' WHERE id='$a'");
}
}
And a table...
id this blah
------------------------
1 that 54
2 that 73
3 there 27
Inside that loop, I also want to find the value stored in the tables blah field from the current record that is being updated.
Whats the most effective way to do this?
You can have your query consist of multiple statements, and the last statement is what is used for the "results".
So, you can just add a "select" statement to the end of the update query and treat it like a normal select statement:
UPDATE table SET this = 'that' WHERE id='$a'; SELECT blah from [your table] WHERE id = '$a'
The advantage with this method is that it doesn't require an additional DB call.
Of course, you will want to be escaping the values put into the SQL statements to prevent SQL injection, but that's another matter.
Update
This was my first second SO answer which I felt needed revising. Searching around, I found a much better answer to your question.
From the accepted answer for question: SQL: Update a row and returning a column value with 1 query
You want the OUTPUT clause
UPDATE Items SET Clicks = Clicks + 1
OUTPUT INSERTED.Name
WHERE Id = #Id
Similar question: Is there a way to SELECT and UPDATE rows at the same time?
Old Answer
Add a SELECT statement to the end of your UPDATE query.
mysql_query("UPDATE table SET this = 'that' WHERE id='$a'; SELECT blah WHERE id='$a';");
This prevents you from ensuring the update took place since mysql_query only returns the last statement's result.
You could also write a custom function that performs both statements but, for instance, won't preform the SELECT if the UPDATE failed, etc.
** Skeleton Function - Not Tested **
function MyUpdate($query, $id){
$retVal = "-1" // some default value
$uResult = mysql_query("UPDATE table SET this = 'that' WHERE id='$a'");
if( $uResult )
$result= mysql_query('SELECT blah WHERE id=$a');
if (!$result) {
die('Invalid query: ' . mysql_error());
}
$retVal = $result;
}
return $retVal;
}
Related
I have a user form that sets a single record "current". No more than one record can be set to current at a time. So, I present the user a single drop down list, they choose the item they want to set current and hit "UPDATE" at the bottom of the form.
The PHP/Mysqli needs to go in and set all records column "current" to a value of 0 then update the one from the form to a value of "1".
Initially, I just did a simple count the number of rows, and run a bunch of queries to update the column to 0 or 1 if the loop counter = the id of the row. Well... that broke quick as I started doing testing on other portions and the index numbers got higher than the total number of rows. Yes, dumb way to do it initially!
Here's what I tried to do with the PHP / MySQL code:
// $link is the database link defined elsewhere. This does work as I use it all over the place
$setCurrent = X; // This is the number passed from my form
$init_query = "SELECT id, current FROM myTable";
if ($stmt = $link->$prepare($init_query) {
$stmt->execute() or die ($stmt->error);
$stmt ->bind_result($id, $current)
while ($stmt->fetch()){
if ($id == $setCurrent){
$update_sql = "UPDATE myTable SET current ='1' WHERE id='".$setCurrent."'";
$stmt2 = $link->prepare($update_sql);
$stmt2->execute;
}
else {
$update_sql = "UPDATE myTable SET current ='0' WHERE id='".$id."'";
$stmt2 = $link->prepare($update_sql);
$stmt2->execute;
}
$stmt->close();
This fails and gives me a Fatal error: Uncaught Error: Call to a member function execute on boolean in .....
I am racking my brain over this and can't figure out what the heck is going on. Its been a few years since I have worked in PHP/MySql and this is my first forray into OO Mysqli. Please be gentle :)
You're missing two closing curly braces. One for the first if() and the other for while()
why do them one at a time? You can do it in one query
$setCurrent = X;
$query = 'UPDATE myTable
SET `current` = (id = :current)';
$stmt = $link->prepare($query);
$stmt->bindValue(':current', $setCurrent);
$stmt->execute();
(and misusing the fact that if id equals $setCurrent, the part between ( ) resolves to true, which is 1.)
some explaining:
SELECT 10=10; would give a kind of "TRUE". But as Mysql does not give true, it give 1.
the same goes for:
SELECT 10=20; This is FALSE, so gives you 0.
Now back to your query: you want to get a value 0 for all record for which id not equal to some-number. And you want 1 when equal:
So you have to compare the column id's value to $setCurrent. When they match you get 1 and you put that 1 into the column "current"
And when they don't match, all other cases, then you get a 0 and that 0 goes into the column Current.
And yes, this could also be done as:
UPDATE mytable
SET `current` = CASE id
WHEN $setCurrent THEN 1
ELSE 0
END CASE
or using IF,
But they other syntax is way shorter
edit
backtics are needed around column name, as current is a reserved word
I have a query like:
SELECT id, name, surname, fromId, toId, msg_text, readed FROM messages WHERE toId = 2;
So I want to update all selected rows.readed = 1. And Query must return all selected rows.
These action must do in one query if possibe.
Sorry for my english
Short answer: No, it is not possible in a single query.
A little less short answer: There is something known as a command-query separation which in short suggests that a command should do something and return nothing and a query should do nothing and return something. I recommend following this principle if you intend on building good software.
I wont get into why this is not possible because I myself am not that much of an SQL guru and I could only guess but I would suggest an easy solution to your problem.
When you get your results then you are most likely processing them in PHP. Assuming the results are sorted in ascending order - on the first iteration grab the minimum id and on the last one grab the maximum id, then run an update query:
UPDATE messages SET readed = 1 WHERE toId = ? AND (id >= <minimum id> AND id <= <maximum id>)
On a side note - name and surname are probably not what you want to store in a messages table.
You can update only with an UPDATE query. An UPDATE query can return only one thing: that is number of affected rows. So, you cannot update and select the value you need in a single query.
Have a look here Update a table then return updated rows in mySQL
You can do that with stored procedure.
Create a stored procedure which executes the update and the select as well.
Eg:
DROP PROCEDURE IF EXISTS myproc;
delimiter //
CREATE PROCEDURE myproc()
begin
set #qry='select id, name, surname, fromId, toId, msg_text, readed from messages where toId = 2';
prepare query from #qry;
execute query;
update messages set readed=1 where toId = 2;
end //
Then you can run the query through this procedure.
Eg:
$sql = "call myproc()";
$result = $conn->query($sql);
if ($result->num_rows > 0) {
// output data of each row
while($row = $result->fetch_assoc()) {
echo "id: " . $row["id"]. " - Name: " . $row["name"]. "<br>";
}
} else {
echo "0 results";
}
I need to update several records in a table, and am hoping to accomplish it in one query.
I have a php array of id's for a few of the records in my table. The array is in a specific order, and I need to update a value for each id with the position/key that the id is in the array. I could easily loop through each value in the array and run a query for each record that needs to be updated, but I am looking for a way to possibly update each record in one query.
The following will give me the desired result, but I am looking for a one query solution.
$ID = array('3','2','6','5','9');
for($i = 0; $i <= 4; $i++){
$q = "UPDATE table SET blah = ".$i." WHERE id = ".$ID[$i];
mysql_query($q) or die();
}
Thanks.
2 queries:
First only needed in case you have used #var already.
SET #var := -1;
And then (note FIND_IN_SET wants a comma-separated string):
UPDATE tablename
SET blah = #var := #var +1
WHERE id IN (3,2,6,5,9)
ORDER BY FIND_IN_SET(id,'3,2,6,5,9');
If you have an array with key=>postition pairs, this could be used:
$array = array(2 => 40,3 => 12,5 => 8,6 => 9,9 =>13129);
mysql_query("
UPDATE bla
SET blah = ELT(
FIELD(id,".implode(',',array_keys($array))."),
".implode(',',$array).")
WHERE id IN (".implode(',',array_keys($array)).")");
A big long ugly if or case statement would do the trick:
UPDATE ...
SET blah = IF(id=3,1,IF(id=2, 2, IF(id=6,3, IF....))))
WHERE id IN (3,2,6,....)
it'd quickly become unmanageable, but it would accomplish things in a single query. A slightly cleaner, more portable alternative:
UPDATE
SET blah = CASE id WHEN 3 THEN 1 WHEN 2 THEN 2 WHEN 6 THEN 3 .... END CASE
WHERE id in (3,2,6,...)
Try this:
INSERT INTO tbl_name (idCol, valCol) VALUES (id1, value1),(id2, value2)
ON DUPLICATE KEY UPDATE
idCol = VALUE(idCol),
valCol = VALUE(valCol)
You could also use a stored procedure, passing it a string of the ID's:
CREATE PROCEDURE updateItems( firstNum INT NOT NULL, ids TEXT NOT NULL) BEGIN
#id := ... # Some expression to get the first ID.
WHILE id != "" DO
SET ids := ... # Some expression to get the rest of the string.
UPDATE table SET blah = firstNum WHERE id = #id;
SET firstNum = firstNum +1;
#id := ... ;
END;
END $$
Also, there was one trick with LAST_INSERT_ID() - if you call it with a param, like LAST_INSERT_ID( 123 ), successive call to LAST_INSERT_ID() will give you 123.
Could be used together with #variables to achieve that goal.
You might get some inspiration here: http://ondra.zizka.cz/stranky/programovani/sql/mysql_stored_procedures.texy
It's impossible in this way ...Well, it's possible but I'd suggest you not to do it, 5 queries aren't horrors
$q = "UPDATE table SET blah = ".$i." WHERE id in ('3','2','6','5','9')";
If you are concerned about performance, you should take a look at using prepared statements and transactions.
There is most likely a solution to doing this in one single query, but it would most likely get really messy.
your better of using foreach then you don't have to set a $i limit.
i think its quick to do it this way
$id = array('3','2','6','5','9');
$i=0;
foreach ($id as $v){
$q = "UPDATE table SET blah = ".$i++." WHERE id = '$v'";
mysql_query($q) or die();
}
I'm trying to update multiple rows in one table in MySQL database by doing this. And its not working.
$query = "UPDATE cart SET cart_qty='300' WHERE cart_id = '21';
UPDATE cart SET cart_qty='200' WHERE cart_id = '23';
UPDATE cart SET cart_qty='100' WHERE cart_id = '24';";
mysql_query($query,$link);// $link is specified above
Anyone know what is wrong with this.
From the PHP documentation:
mysql_query() sends a unique query (multiple queries are not supported)
The ; separates SQL statements, so you need to separate the queries if you want to continue using the mysql_query function...
mysql_query can't use multiple queries.
The easiest thing is to just run them separately. I believe you can do multi query but I haven't tried it.
$updateArray = array(21=>300,23=>200,24=>100);
foreach($updateArray as $id=>$value)
{
$query = "UPDATE cart SET cart_qty='$value' WHERE cart_id = '$id'";
mysql_query($query,$link);// $link is specified above
}
This will accept a combination of IDs and their corresponding cart value. Looping though, it builds the query and executes it. The array can then come from a variety of sources (results from another query, form inputs or, as in this case, hard-coded values)
Update:
If you really need to execute all in one, heres the PHP info on multi query:
mysqli::multi_query
You can do it this way:
UPDATE table
SET col1 = CASE id
WHEN id1 THEN id1_v1,
WHEN id2 THEN id2_v1
END
col2 = CASE id
WHEN id1 THEN id1_v2,
WHEN id2 THEN id2_v2
END
WHERE id IN (id1, id2)
This example shows updating two different columns in two different rows so you can expand this to more rows and columns by cludging together a query like this. There might be some scaling issues that makes the case statement unsuitable for a very large number of rows.
You'll need to send them as separate queries. Why not add the queries as strings to an array, then iterate through that array sending each query separtely?
Also check this thread for another idea
This isn't the best method.. But if you need to do multiple queries you could use something like...
function multiQuery($sql)
{
$query_arr = explode(';', $sql);
foreach ($query_arr as $query)
{
mysql_query($query);
}
}
another example of a helper query
function build_sql_update($table, $data, $where)
{
$sql = '';
foreach($data as $field => $item)
{
$sql .= "`$table`.`$field` = '".mysql_real_escape_string($item)."',";
}
// remove trailing ,
$sql = rtrim($sql, ',');
return 'UPDATE `' . $table .'` SET '.$sql . ' WHERE ' .$where;
}
echo build_sql_update('cart', array('cart_qty' => 1), 'cart_id=21');
Hey, I have a field called STATUS and it is either 1 to show or 0 to hide. My code is below. I am using an edit in place editor with jQuery. Everytime you update it creates a new ROW which I want, but I want only the new one to have STATUS = 1 and the others to 0. Any ideas on how I would do that?
<?php
include "../../inc/config.inc.php";
$temp = explode("_", $_REQUEST['element_id'] );
$field = $temp[0];
$id = $temp[1];
$textboxval = stripslashes(mysql_real_escape_string(preg_replace('/[\$]/',"",$_REQUEST["update_value"])));
$query = "INSERT INTO notes ($field,status,date,c_id) VALUES ('$textboxval','1',NOW(),'$id')";
mysql_query($query);
echo($_REQUEST['update_value']);
?>
I am not sure exactly what you mean - do you want to make all the entries except the new one have status = 0? If so, just issue an update before the insert:
UPDATE notes SET status = 0
However, I should also note that you have a potential SQL injection to worry about. By stripping slashes after applying "mysql real escape string", you are potentially allowing someone to put text in your SQL statement that will execute an arbitrary SQL statement.
Something like this, sorry for the post before, I mis read it the first time then went back:
<?php
include "../../inc/config.inc.php";
$temp = explode("_", $_REQUEST['element_id'] );
$field = $temp[0];
$id = $temp[1];
$textboxval = mysql_real_escape_stringstripslashes((preg_replace('/[\$]/',"",$_REQUEST["update_value"])));
// set older entries to 0 - to not show but show in history
$hide_notes = "UPDATE notes SET status = 0";
mysql_query($hide_notes);
// add new entry with status of 1 to show only latest note
$query = "INSERT INTO notes ($field,status,date,c_id) VALUES ('$textboxval','1',NOW(),'$id')";
mysql_query($query);
echo($_REQUEST['update_value']);
?>
i just ran in to a problem I didn't of the set up of my table doesn't allow me to show more than one client a time and i will be having numerous clients, my bad on planning ha
You really want to get the ID of the newly generated row and then trigger an UPDATE where you all rows where the ID is not the new row, e.g.
UPDATE notes SET status = 0 WHERE id != $newly_generated_id
If the ID column in your table is using AUTO_INCREMENT you can get its ID via "SELECT LAST_INSERT_ID()" and then use the return value in that statement in your UPDATE statement.
Pseudo code:
$insert = mysql_query("INSERT INTO ...");
$last_id = mysql_query("SELECT LAST_INSERT_ID()");
$update = mysql_quqery("UPDATE notes SET status = 0 WHERE id != $last_id");
The only caveat to this approach is where you might have a brief moment in time where 2 rows have status=1 (the time between your INSERT and the UPDATE). I would wrap all of this in a transaction to make the whole unit more atomic.