MySQL: how to update column using value before change - mysql

There is a table with three column: id, field1, field2.
And there is a row: id=1, field1=1, field2=1.
Run a update SQL: UPDATE my_table SET field1=field2+1, field2=field1+1 WHERE id=1;
I expected the result is: id=1, field1=2, field2=2. But in fact I got: id=1, field1=2, field2=3. Because when calculating field2=field1+1, the value of field1 has changed!
I figure out a SQL to solve this problem:
UPDATE my_table dest, (SELECT * FROM my_table) src
SET dest.field1=src.field2+1, dest.field2=src.field1+1
WHERE dest.id=1;
However I want to insert a record, and if the row was existed then do a update just like above.
INSERT INTO my_table (id, field1, field2) VALUES(1, 1, 1)
ON DUPLICATE KEY UPDATE
field1=field2+1, field2=field1+1;
This SQL has problem same as the first SQL. So how can I do this update using the value before change with ON DUPLICATE KEY UPDATE clause?
Thanks for any help!

Couldn't think of anything else but a temp variable. However, couldn't think of a way to make SQL syntax work, other than this:
set #temp = 0;
update test.test set
f1 = (#temp:=f1),
f1 = f2 + 1,
f2 = #temp + 1
where id = 1;
Hope this helps, and hope even more it helps you find a better way :)

I find a trick way to do this.
Use the IF clause to create temp variable. Field update use temp variable to calculate.
INSERT INTO my_table (id, f1, f2) VALUES(1, 1, 1)
ON DUPLICATE KEY UPDATE
id=IF((#t1:=f1 & #t2:=f2), 1, 1), f1=#t2+1, f2=#t1+1;
There is some point to notice:
The performance is a bit slow. Especially copy TEXT value to temp variable.
If field id need to use IF clause, the expr will be more complicated like:
((#t1:=f1 & #t2:=f2) || TRUE) AND (Your Condition)

Related

INSERT INTO with Increment variable

I would like to have an INSERT INTO query which one of the fields I update is a calculated var 'mycount' - which will be the number of the inserted row in the query.
For example:
If I insert 3 rows, I'd like this var to be '1' for the first row inserted, '2' for the second, and so forth.
SET #mycount=0;
INSERT INTO my_table
(#mycount,field1,field2,field3...)
SET #mycount=#mycount+1;
SELECT #mycount,field1,field2,field3..
FROM my_table
WHERE id IN (id1,id2,id3..);
This code returns an error.
How can I declare a variable inside an INSERT INTO query and have it incremented with every row inserted ?
IMPORTANT - I do not need an AUTO-INCREMENT column - this is a part of a calculation that needs to be performed only in this specific INSERT INTO query, and it is only part of the calculation.
What I need is really a calculation of (number_of_inserted_row+some_other_calculation) but I just simplified it for the sake of the question.
Well, usually an auto_increment column is used for this. If you don't want to for whatever reason, you can do it like this:
INSERT INTO my_table
(your_quasi_auto_increment_column, field1, field2, field3...)
SELECT (#mycount := #mycount + 1) + <other_calculation>, field1, field2, field3..
FROM my_table
, (SELECT #mycount := 0) var_init_query_alias
WHERE id IN (id1,id2,id3..);
you can do this using add new filed which you want to insert as like count_number and define auto increment this filed and not need to insert in this query
SET #test=1;
INSERT INTO test (`test`,`test2`,`test3`)
SELECT (#test := #test +1) AS `test`,`test2`,`test3`
FROM test
if you want to add new file then
then check this code
SET #count_value=0;
INSERT INTO test (`count_value`,`test`,`test2`,`test3`)
SELECT (#count_value := #count_value +1) AS `count_value`,`test`,`test2`,`test3`
FROM test
in my_table1 add field count_number and type int and add auto increment then it will work

Can you use aggregate values within ON DUPLICATE KEY

I am trying to write a query similar to:
INSERT INTO SomeTable(field1, field2)
SELECT 'blah' AS field1,
MAX(AnotherTable.number) AS field2
FROM AnotherTable
ON DUPLICATE KEY
UPDATE field1= 'blah', field2 = MAX(AnotherTable.number)
I get Error Code: 1111
Invalid use of group function.
Reading through the MySql documentation:
http://dev.mysql.com/doc/refman/5.1/en/insert-select.html
the lines of interest are:
"In the values part of ON DUPLICATE KEY UPDATE, you can refer to columns in other tables, as long as you do not use GROUP BY in the SELECT part. One side effect is that you must qualify nonunique column names in the values part. "
Is this the problem I am seeing? I am not specifically doing a GROUP BY in the Select statement, but by using an aggregate function (Max), then I may be grouping implicitly.
If anyone knows for sure if I am implicitly doing a GROUP BY or if there is any other way I can get the desired result I would be very greatful.
I know I am answering my own question here but...
This eventually got it working (thanks to: a broken link)
INSERT INTO SomeTable(field1, field2)
SELECT 'blah' AS field1,
MAX(AnotherTable.number) AS field2
FROM AnotherTable
ON DUPLICATE KEY
UPDATE field2 = values(field2)
Please have a try if this works:
INSERT INTO SomeTable(field1, field2)
SELECT * FROM (
SELECT * FROM (
SELECT 'blah' AS field1,
MAX(AnotherTable.number) AS field2
FROM AnotherTable
) sq
) sq2
ON DUPLICATE KEY
UPDATE field1= 'blah', field2 = sq2.field2
Not sure if 2 times the subquery is needed. I usually use this to circumvent MySQLs limitation to not be able to update the table with values I read from the same table. Not sure if this works here, too.

MySQL direct INSERT INTO with WHERE clause

I tried googling for this issue but only find how to do it using two tables, as follows,
INSERT INTO tbl_member
SELECT Field1,Field2,Field3,...
FROM temp_table
WHERE NOT EXISTS(SELECT *
FROM tbl_member
WHERE (temp_table.Field1=tbl_member.Field1 and
temp_table.Field2=tbl_member.Field2...etc.)
)
This worked for one scenario,But now my interest is to upload data directly from the program itself without using two tables. What i want is to upload the data which is not in the table. The sql i had in my head was like the following,
INSERT INTO tbl_member (SensorIdValue, DataTimeValue, DataInValue, IncompleteValue, SpiValue, InfoValue)
VALUES ('Sensor.org', '20121017150103', 'eth0','','','')
WHERE (SensorIdValue != 'Sensor.org'AND DataTimeValue != '20121017150103'AND DataInValue != 'eth0'AND IncompleteValue != ''AND SpiValue != ''AND InfoValue != '');
But it's wrong.. may i know the proper way of doing it please, Thank you very much :)
INSERT syntax cannot have WHERE clause. The only time you will find INSERT has WHERE clause is when you are using INSERT INTO...SELECT statement.
The first syntax is already correct.
you can use UPDATE command.
UPDATE table_name SET name=#name, email=#email, phone=#phone WHERE client_id=#client_id
INSERT syntax cannot have WHERE but you can use UPDATE.
The syntax is as follows:
UPDATE table_name
SET column1 = value1, column2 = value2, ...
WHERE condition;
If I understand the goal is to insert a new record to a table but if the data is already on the table: skip it! Here is my answer:
INSERT INTO tbl_member
(Field1,Field2,Field3,...)
SELECT a.Field1,a.Field2,a.Field3,...
FROM (SELECT Field1 = [NewValueField1], Field2 = [NewValueField2], Field3 = [NewValueField3], ...) AS a
LEFT JOIN tbl_member AS b
ON a.Field1 = b.Field1
WHERE b.Field1 IS NULL
The record to be inserted is in the new value fields.
Example of how to perform a INSERT INTO SELECT with a WHERE clause.
INSERT INTO #test2 (id) SELECT id FROM #test1 WHERE id > 2
merge into table2 chg
using table1 src on src.id = chg.id
when not matched then
insert (chg.id, chg.desc)
values (src.id, src.desc)
when matched then
update set chg.desc = src.desc;
The INSERT INTO Statement
The INSERT INTO statement is used to insert a new row in a table.
SQL INSERT INTO Syntax
It is possible to write the INSERT INTO statement in two forms.
The first form doesn't specify the column names where the data will be inserted, only their values:
INSERT INTO table_name
VALUES (value1, value2, value3,...)
The second form specifies both the column names and the values to be inserted:
INSERT INTO table_name (column1, column2, column3,...)
VALUES (value1, value2, value3,...)

Insert a greatest value (max+1)

I have a table (foo) where I already have a PK on id:
id name rank
-----------------------
1 AAAA 2
2 BBBB 1
I want to insert a new row where I know the values of column id and name and want rank to take a value greater than any other value in the same column in preceding rows (similar to what auto_increment does for us).
i.e. if I were to add a row with value = CCCC, the rank column should have a value 3. I need to do this in a compound statement if possible. I tried the following which does not work.
insert into foo (`name`, `rank`)
values ('CCCC', (select max(`rank`) from `foo`))
Which gives me the following error:
You can't specify target table 'foo' for update in FROM clause
Note: I would ideally like to have the rank column as an auto_increment field, but apparently that's not allowed either, since I already have a PK.
PS: I need to be able to execute this statement from PHP without using stored procedures.
Try this first, it being derived instantly from your post:
INSERT INTO foo (`name`, `rank`)
SELECT 'CCCC', (MAX(`rank`) + 1) AS rank
FROM `foo`
Then using PDO, I think this'll work:
...
$sql = "INSERT INTO foo (`name`, `rank`) SELECT ?, (MAX(`rank`) + 1) AS rank FROM `foo`"
$name = "CCCC";
$st = $pd->prepare($sql);
$st->bindValue(1, $name);
try {
$retval = $st->execute();
} catch (PDOException $pdoex) {
...
Not sure if I got in syntactically correct but that should be about the gist of it ... I think
Err.. lemme know if the SQL works, at least :D

Is it really no solution to update multiple records in MySQL?

I want to do all these update in one statement.
update table set ts=ts_1 where id=1
update table set ts=ts_2 where id=2
...
update table set ts=ts_n where id=n
Is it?
Use this:
UPDATE `table` SET `ts`=CONCAT('ts_', `id`);
Yes you can but that would require a table (if only virtual/temporary), where you's store the id + ts value pairs, and then run an UPDATE with the FROM syntax.
Assuming tmpList is a table with an id and a ts_value column, filled with the pairs of id value, ts value you wish to apply.
UPDATE table, tmpList
SET table.ts = tmpList.ts_value
WHERE table.id = tmpList.id
-- AND table.id IN (1, 2, 3, .. n)
-- above "AND" is only needed if somehow you wish to limit it, i.e
-- if tmpTbl has more idsthan you wish to update
A possibly table-less (but similar) approach would involve a CASE statement, as in:
UPDATE table
SET ts = CASE id
WHEN 1 THEN 'ts_1'
WHEN 2 THEN 'ts_2'
-- ..
WHEN n THEN 'ts_n'
END
WHERE id in (1, 2, ... n) -- here this is necessary I believe
Well, without knowing what data, I'm not sure whether the answer is yes or no.
It certainly is possible to update multiple rows at once:
update table table1 set field1='value' where field2='bar'
This will update every row in table2 whose field2 value is 'bar'.
update table1 set field1='value' where field2 in (1, 2, 3, 4)
This will update every row in the table whose field2 value is 1, 2, 3 or 4.
update table1 set field1='value' where field2 > 5
This will update every row in the table whose field2 value is greater than 5.
update table1 set field1=concat('value', id)
This will update every row in the table, setting the field1 value to 'value' plus the value of that row's id field.
You could do it with a case statement, but it wouldn't be pretty:
UPDATE table
SET ts = CASE id WHEN 1 THEN ts_1 WHEN 2 THEN ts_2 ... WHEN n THEN ts_n END
I think that you should expand the context of the problem. Why do you want/need all the updates to be done in one statement? What benefit does that give you? Perhaps there's another way to get that benefit.
Presumably you are interacting with sql via some code, so certainly you can simply make sure that the three updates all happen atomically by creating a function that performs all three of the updates.
e.g. pseudocode:
function update_all_three(val){
// all the updates in one function
}
The difference between a single function update and some kind of update that performs multiple updates at once is probably not a very useful distinction.
generate the statements:
select concat('update table set ts = ts_', id, ' where id = ', id, '; ')
from table
or generate the case conditions, then connect it to your update statement:
select concat('when ', id, ' then ts_', id) from table
You can use INSERT ... ON DUPLICATE KEY UPDATE. See this quesion: Multiple Updates in MySQL
ts_1, ts_2, ts_3, etc. are different fields on the same table? There's no way to do that with a single statement.