简体   繁体   中英

Is it possible to insert into mysql a value that's calculated with a condition?

I have some C++ code which uses a MySQL connector. Our database is innodb.

The goal of the code is to locate a row, and if it exists update it with new values, and if it doesn't exist do an insert.

Currently, it is doing an explicit: "select...where..." followed by an insert or an update depending on whether it finds the record.

I discovered "INSERT...ON DUPLICATE KEY UPDATE" recently: https://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html and was excited to apply it here, thinking we could improve performance with this.

First, am I right to presume that performance would likely improve?

Second, I have a bit of a problem. One of the fields being inserted is the result of dividing two other fields for the same record. And I need to account for the case of dividing by 0.

I'm trying to do something like this:

"INSERT INTO table (time_stamp, in_bytes, out_bytes, pct) VALUES(date + "," + inBytes + "," + outBytes + ", out_bytes/in_bytes)  ON DUPLICATE KEY UPDATE in_bytes = in_bytes + 0, out_bytes = out_bytes + 0, pct = out_bytes/in_bytes;"

Unfortunately, if in_bytes is 0, I get the following error: "ERROR 1048 (23000): Column 'pct' cannot be null".

Can anything be done about this? In a way that improves performance beyond our original method? I had thought about having a trigger for calculating the pct field but that seems like it might not improve performance.

You can use whatever expression you want. In this case you can use IF(condition,value when true,value when false) :

pct = IF(in_bytes != 0, out_bytes/in_bytes, 42)

Or for bonus points you can do the same with COALESCE :

pct = COALESCE(out_bytes/in_bytes, 42)

As a general answer, using on duplicate update should slightly improve your insertion performance, as it saves the roundtrip between the database and your code you get with selecting. It's also an atomic operation, alike the approach of using a query, so it solves the potential bug when you have two threads/programs that query, each decide there's no record with the given timestamp, and both attempt to insert it.

With regard to pct , the correct answer would probably be not to have it as a field in the table at all. Instead, you can calculate it when querying. The case of in_bytes being 0 could be solved with a case expression:

SELECT time_stamp, in_bytes, out_bytes
       CASE in_bytes WHEN 0 THEN -1 -- Or some other meaningful default
                     ELSE out_bytes/in_bytes
       END AS pct
FROM   my_table

If you absolutely must have it as a field, the same case expression could be applied to the on duplicate key clause, of course.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM