In MySQL, is it possible to update the selected records on the same query?
For eg., If the query
SELECT *
FROM `table`
WHERE field = "value"
LIMIT 0,2
Return two rows, then on the same query, i need to increment the table's count field by 1. Is it possible?
Yes its possible you can write as UPDATE query as:
UPDATE my_table
SET count = count + 1
WHERE field = "value"
LIMIT 2;
or for LIMIT with offset try:
UPDATE my_table a
INNER JOIN (SELECT id FROM my_table WHERE field = "value" LIMIT 0, 2) b
ON a.id = b.id
SET count = count + 1;
It's not possible. The verb SELECT only retrieves data (without modifying it); and the verb UPDATE only modifies data (without retrieving it). There is no MySQL verb that will perform both actions. You will have to use two separate statements.
However, those two statements can be encapsulated within a transaction (if supported by your storage engine) to ensure that they are conducted atomically and/or could be invoked from within a stored procedure to simplify the command that must be issued by your client. Combining the two one would have:
DELIMITER ;;
CREATE PROCEDURE select_and_update(value TEXT)
BEGIN
START TRANSACTION;
SELECT * FROM `table` WHERE field = value LIMIT 0,2;
UPDATE `table` SET count = count + 1 WHERE ...;
COMMIT;
END;;
DELIMITER ;
Then your client need merely do:
CALL select_and_update('value');
Related
Update table set Style='new' where id=(SELECT MAX(id) From table);
This is my query. But not working in mysql.
Error shows: You can't specify target table 'table' for update in FROM clause
Please help.
You can store the result of the subquery in a session variable, like so:
SELECT MAX(id) INTO #maxID
FROM table
;
UPDATE table
SET Style='new'
WHERE id=#maxID
;
Note that the operation is no longer "atomic"; depending on the activity going on, it is potentially possible for that MAX(id) to change between the SELECT and the UPDATE.
Another possibility is:
UPDATE table
SET Style = 'new'
ORDER BY id DESC
LIMIT 1
;
But I tend to (for no particular reason) be averse to such queries.
This may seem like a repeat question, but it always seems to be questions involving more than one table. When a row in a table is selected, I will also need to +1 the view count in the same row. I know I can't use a trigger or two statements in the same query, but could both of these things be done with a single connection to the database? What would the preferred method be to both select a row and then +1 the view field?
It can be done in the same connection, but I can't think of a way for that to be done using one query.
Here is how you would do that in a single transaction;
START TRANSACTION;
UPDATE tbl SET view=view+1 WHERE id = 10;
SELECT * FROM tbl WHERE id = 10;
COMMIT;
A second "better" method you can do that which eliminates having to read the tbl table twice.
UPDATE tbl
SET view = (#viewsCount := view + 1)
WHERE id = 10;
And to get the new value of the views count I would do something like this
SELECT #viewsCount;
A third way would be by utilizing the LAST_INSERT_ID() function like so
UPDATE tbl
SET view = LAST_INSERT_ID(view) + 1
WHERE id = 10;
Then to get the new view count you will need to execute this query immediately after the update. you can not execute any other queries after the update otherwise you will not get the intended value.
SELECT LAST_INSERT_ID();
I wonder why MySQL does not allow table locking inside a stored procedure.
I have the following SQL statements inside my stored procedure:
-- Total amount of money for comments
start transaction;
select #num_comments := count(*)
from `comment` c
where
c.user_id = user_id and
c.payment_rejection = 'NO' and
c.is_recorded = 0;
update `user` u set account_balance += u.comment_price * #num_comments where u.user_id = user_id;
update `comment` c set is_recorded = 1 where c.user_id = user_id and c.payment_rejection = 'NO' and c.is_recorded = 0;
commit;
So I have to lock table comment to prevent any writing to it for it may cause the number of rows selected in the first SQL statement be different from the number of actually updated.
Sir, in your code you can use ROW_COUNT() function instead of SELECT count(*)
According to documentation: http://dev.mysql.com/doc/refman/5.0/en/information-functions.html#function_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.
start transaction;
update `comment` c
set is_recorded = 1
where c.user_id = v_user_id
and c.payment_rejection = 'NO'
and c.is_recorded = 0;
SET #num_comments = row_count();
update `user` u
set account_balance += u.comment_price * #num_comments
where u.user_id = v_user_id;
commit;
In this way there is no need to lock tables, the number of rows cannot change between statements, and a bonus is a higher speed of the whole transaction.
Some comments:
The user_id column is ambiguous in the query:
where u.user_id = user_id;
and the update command updates the whole table instead of rows belong to one user only.
Don't use the same names for variables in the procedure as columns names in the table, the easiest way is to prepend some prefix to variable names to avoid ambiguity, for example:
where u.user_id = var_user_id;
I am trying to combine these two queries in twisted python:
SELECT * FROM table WHERE group_id = 1013 and time > 100;
and:
UPDATE table SET time = 0 WHERE group_id = 1013 and time > 100
into a single query. Is it possible to do so?
I tried putting the SELECT in a sub query, but I don't think the whole query returns me what I want.
Is there a way to do this? (even better, without a sub query)
Or do I just have to stick with two queries?
Thank You,
Quan
Apparently mysql does have something that might be of use, especially if you are only updating one row.
This example is from: http://lists.mysql.com/mysql/219882
UPDATE mytable SET
mycolumn = #mycolumn := mycolumn + 1
WHERE mykey = 'dante';
SELECT #mycolumn;
I've never tried this though, but do let me know how you get on.
This is really late to the party, but I had this same problem, and the solution I found most helpful was the following:
SET #uids := null;
UPDATE footable
SET foo = 'bar'
WHERE fooid > 5
AND ( SELECT #uids := CONCAT_WS(',', fooid, #uids) );
SELECT #uids;
from https://gist.github.com/PieterScheffers/189cad9510d304118c33135965e9cddb
You can't combine these queries directly. But you can write a stored procedure that executes both queries. example:
delimiter |
create procedure upd_select(IN group INT, IN time INT)
begin
UPDATE table SET time = 0 WHERE group_id = #group and time > #time;
SELECT * FROM table WHERE group_id = #group and time > #time;
end;
|
delimiter ;
So what you're trying to do is reset time to zero whenever you access a row -- sort of like a trigger, but MySQL cannot do triggers after SELECT.
Probably the best way to do it with one server request from the app is to write a stored procedure that updates and then returns the row. If it's very important to have the two occur together, wrap the two statements in a transaction.
There is a faster version of the return of updated rows, and more correct when dealing with highly loaded system asks for the execution of the query at the same time on the same database server
update table_name WITH (UPDLOCK, READPAST)
SET state = 1
OUTPUT inserted.
UPDATE tab SET column=value RETURNING column1,column2...
Can I say that one of many ways to optimize mysql is to reduce the number of queries?
If that so, can I do this:
- Select "data" => $A from table X
- Update $A from table Y
- Delete $A from table X
in one query?
You can't reduce the number of queries - they all do different things - but you could reduce the number of round trips to the database and the number of parses by wrapping it all as a PLSQL function.
However you can't select the data after you've deleted it.....but consider:
CREATE PROCEDURE s_u_d(a)
BEGIN
UPDATE tab_x SET tab_x.avalue=1 WHERE tab_x.another=a;
DELETE FROM tab_y WHERE tab_y.avalue=a;
SELECT *
FROM tab_x
WHERE tab_x.another=a;
END;
NB - you can also run multiple selects in the same procedure and handle multiple, different shaped result sets, e.g. see this page
NO,
only can combine
DELETE and SELECT
UPDATE and SELECT
This is not a proper way for mysql optimization simply
because each query come with different query cost.
And in myisam, it involve table level locking for write
Example for UPDATE and SELECT
/* this will update TABLE_A if ID in TABLE_B exist in TABLE_A */
UPDATE TABLE_A, TABLE_B
SET TABLE_A.SOME_COLUMN=TABLE_B.SOME_COLUMN
WHERE TABLE_A.ID=TABLE_B.ID
/* or */
UPDATE TABLE_A
SET SOME_COLUMN = (SELECT SOME_COLUMN_B FROM TABLE_B WHERE ... LIMIT 1)
Example for DELETE and SELECT
DELETE FROM TABLE_A WHERE TABLE_A IN(SELECT ID FROM TABLE_B)
Create a stored procedure:
DELIMITER //
create procedure empproc(in name varchar(255),in fathername varchar(255),in password varchar(255))
begin
Select * from xemp where uname = name and fname = fathername;
insert into xemp values(name,fathername,password);
end //
delimiter ;
Java Code.....
import java.sql.*;
public class StoredProcedure {
public static void main(String a[])throws Exception {
Class.forName("com.mysql.jdbc.Driver").newInstance();
Connection conn=DriverManager.getConnection("jdbc:mysql://localhost:3306/01jim2010","root","");
CallableStatement calstat=conn.prepareCall("{call empproc(?,?,?)}");
calstat.setString(1,"Jimit");
calstat.setString(2,"Temp");
calstat.setString(3,"Temp");
ResultSet rs = calstat.executeQuery();
conn.close();
calstat.close();
System.out.println("Your data has been inserted into table.");
}
}