it is possible in one SQL statement to insert a record then take the autoincrement id, and update for the same record one specific column
with this autoincrement value.
Thanks in Advance.
Strictly speaking you can not do it in a single SQL statement (as others have already pointed out).
However, since you mention that you want to avoid making changes to legacy application let me clarify some options that might work for you.
If you had a trigger on the table that would update the second column, then issuing single insert will give you what you want and you might not need to change anything in the application
If possible, you could rename the table and in its place put a VIEW with the same name. With such simple view it might be transparent to your application (not sure if VIEW would remain updateable with your framework, but generally speaking it should)
Finally, with mysqli library you are free to issue multiple SQL statements, so it will be a single call to the database - which might be enough for you, depending on how exactly you define 'single statement'
None of the above will never be comparable to fixing the application in terms of maintainability for the guy who will inherit your code.
Doing an insert automatically fills in the value for an auto_increment column (just define it to use AUTO_INCREMENT). There is no need to have the same value twice in one record.
Doing an UPDATE + INSERT together is not possible in a single query.
I found this artcile that may be of interest to you:
http://www.daniweb.com/forums/thread107837.html
They suggest it is possible to do the insert and update in one query.
They show a query like:
INSERT INTO table (FIELD) VALUES (value) ON DUPLICATE KEY UPDATE FIELD=value
I hope this helps and to all the nay sayers, anything is possible.
While I believe it is possible, your safest bet is probably to split this operation up into three stages.
I successfully did this on my own database locally with this code:
INSERT INTO status set status_id = 5 ON DUPLICATE KEY UPDATE status_id=5;select last_insert_id()
You should be able to transform it to work for you.
You can write a AFTER INSERT trigger which takes max(id) and updates the record
That's not possible at all.
You have to either do this separately or you may create a function/stored procedure to achieve this mission.
Multiple statements can be separated by a semicolon, but I believe you need to use a function in PHP to get the autoincrement value. Your best bet might be to use a stored procedure.
Related
Let's say I have dynamic numbers with unique id's to them.
I'd like to insert them into database. But if I already have that certain ID (UNIQUE) I need to add to the value that already exists.
I've already tried using "ON KEY UPDATE" ,but it's not really working out. And selecting the old data so we could add to it and then updating it ,is not efficient.
Is there any query that could do that?
Incrementing your value in your application does not guarantee you'll always have accurate results in your database because of concurrency issues. For instance, if two web requests need to increment the number with the same ID, depending on when the computer switches the processes on the CPU, you could have the requests overwriting each other.
Instead do an update similar to:
UPDATE `table` SET `number` = `number` + 1 WHERE `ID` = YOUR_ID
Check the return value from the statement. An update should return the number of rows affected, so if the value is 1, you can move on happy to know that you were as efficient as possible. On the other hand, if your return value is 0, then you'll have to run a subsequent insert statement to add your new ID/Value.
This is also the safest way to ensure concurrency.
Hope this helps and good luck!
Did something different. Instead of updating the old values ,I'm inserting new data and leaving old one ,but using certain uniques so I wouldn't have duplicates. And now to display that data I use a simple select query with sum property and then grouping it by an id. Works great ,just don't know if it's the most efficient way of doing it.
I'm still new and some of the right coding practices escape me. Documentation on this particular situation is weak, so I would like to get some advice/suggestions from you experts :) on the following.
I have an API that allows users to update 2 tables in one call. One is a SUMMARY table and the other is a DETAIL table with an FK to the SUMMARY table.
What I have my code doing is I do an UPSERT (insert/update) to the SUMMARY table, grab the insert_id and then delete the records from the DETAIL table, then insert the ones I need (referencing SUMMARY with the fk of course).
However, in the instance that there are no changes to SUMMARY data - insert_id returns 0. This seems expected as no row was updated/inserted.
So here is my question:
Should I be doing a full read of the tables and comparing data prior to this update/delete/insert attempt? Or is there another nifty way of grabbing the id of the SUMMARY that was a duplicate of the UPSERT attempt? I feel that my users will 'almost' ALWAYS be changing the SUMMARY and DETAIL data when using this API.
What is the correct coding practice here? Is the extra read worth it every time? Or should I read only if insert_id = 0?
Thoughts? My biggest problem is that I don't know what the magnitude difference of a read vs a write is here - especially since I don't believe the API will be called much without having changed values.
Again my options are:
Read db and compare to see if there is a diff
Insert/Update accordingly
Attempt Insert/update.
if (insert_id = 0) then read db to get summary id for details table
copmlete process
Attempt Insert/Update
use ?something? to get id of summary of record that was duplicate (and prevented insert/update)
use the id to complete steps.
If the id you need is an auto_increment field, option 4 (do everything inside DB with 1 execute action) 100% of the time. This is the general SQL structure you need:
Insert into summary (primaryKey, fieldA, fieldB) values (NULL, valueA, valueB) on duplicate key update primaryKey=LAST_INSERT_ID(primaryKey), fieldA = fieldA, fieldB=fieldB;
If you then do SELECT LAST_INSERT_ID() it'll give you either the successful inserted id or ,if duplicate, the duplicate entrie's id. So do something like:
delete from detail where summary_id = LAST_INSERT_ID();
At the companies I've worked for, option 1 is usually the one I've seen used if you're wanting to compare record by record. This can be implemented either in a stored proc or in the code itself. Depends on the context of what "same" means. If it's raw values, then sql is probably the easiest. If there's a context in addition to what the database has, you'll want to do it at the code level. Hope that helps.
Is it possible to UPDATE and then INSERT where row exists in mysql? I have this query,
$q = $dbc -> prepare("UPDATE accounts SET lifeforce = maxLifeforce, inHospital = 0 WHERE hospitalTime <= NOW() AND inHospital = 1");
$q -> execute();
How can I either get the primary key into an associative array to then do an insert for each item in the array, or do an UPDATE AND INSERT?
Or does it involve doing a SELECT to get all that match criteria, then UPDATE then INSERT using array from the select? This seems rather a long way to do it?
Basically I need to INSERT onto another table using the same primary keys that get updated.
Or does it involve doing a SELECT to get all that match criteria, then UPDATE then INSERT using array from the select?
Yes, sorry, that's the main way.
Another approach is to add a column called (say) last_updated, that you set whenever you update the column. You can then use that column in a query that drives your insert. That would have other advantages — I find last_updated columns to be useful for many things — but it's overkill if this is the only thing you'd ever use it for.
Edited to add: Another option, which just occurred to me, is to add a trigger to your accounts table, that will perform the insert you need. That's qualitatively different — it causes the insertion to be a property of accounts, rather than a matter of application logic — but maybe that's what you want? Even the most extreme partisans of the "put-all-constraints-in-the-database-so-application-logic-never-introduces-inconsistency" camp are usually cautious about triggers — they're really not a good way to implement application logic, because it hides that logic somewhere that no-one will think to look for it. But if the table you're inserting into is some sort of account_history table that will keep track of all changes to account, then it might be the way to go.
You can use a multiple table update as written in the manual: http://dev.mysql.com/doc/refman/5.0/en/update.html
If the second table needs an insert, you probably would have to do it manually.
You can use the mysqli_last_id function:
http://php.net/manual/en/mysqli.insert-id.php
Also, when running consecutive queries like that, I'd recommend using transactions:
http://www.techrepublic.com/article/implement-mysql-based-transactions-with-a-new-set-of-php-extensions/6085922
First of all, let me just say that I'm using the PHP framework Yii, so I'd like to stay within its defined set of SQL statement if possible. I know I could probably create one huge long SQL statement that would do everything, but I'd rather not go there.
OK, imagine I have a table Users and a table FavColors. Then I have a form where users can select their color preferences by checking one or more checkboxes from a large list of possible colors.
Those results are stored as multiple rows in the FavColors table like this (id, user_id, color_id).
Now imagine the user goes in and changes their color preference. In this scenario, what would be the most efficient way to get the new color preferences into the database?
Option 1:
Do a mass delete of all rows where user_id matches
Then do a mass insert of all new rows
Option 2:
Go through each current row to see what's changed, and update accordingly
If more rows need to be inserted, do that.
If rows need to be deleted, do that.
I like option one because it only requires two statements, but something just feels wrong about deleting a row just to potentially put back almost the exact same data in. There's also the issue of making the ids auto-increment to higher values more quickly, and I don't know if that should be avoided whenever possible.
Option 2 will require a lot more programming work, but would prevent situations where I'd delete a row just to create it again. However, adding more load in PHP may not be worth the decrease in load for MySQL.
Any thoughts? What would you all do?
UPDATE is by far much faster. When you UPDATE, the table records are just being rewritten with new data. And all this must be done again on INSERT.
When you DELETE, the indexes should be updated (remember, you delete the whole row, not only the columns you need to modify) and data blocks may be moved (if you hit the PCTFREE limit). Also deleting and adding new changes records IDs on auto_increment, so if those records have relationships that would be broken, or would need updates too. I'd go for UPDATE.
That's why you should prefer INSERT ... ON DUPLICATE KEY UPDATE instead of REPLACE.
The former one is an UPDATE operation in case of a key violation, while the latter one is DELETE / INSERT
UPDATE: Here's an example INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
For more details read update documentation
Philip,
Have you tried doing prepared statements? With prepared statements you can batch one query with different parameters and call it multiple times. At the end of your loop, you can execute all of them with minimal amount of network latency. I have used prepared statements with php and it works great. Little more confusing than java prepared statements.
As an example, when inserting a record into a table with a unique index, is it best to test first? e.g.,
$mysqli->query('SELECT email FROM tblUser WHERE email = 'foo#bar.org');
then make sure 0 rows are returned, then do the insert?
$mysqli->query('INSERT INTO tblUser ...');
Or is it better to just skip the test and handle the error in the event there's a duplicate entry?
THANKS!
It's better to insert and handle any duplicate key errors.
The reason is that if you test first, some other client can still insert the value in the brief moment between your test and your insert. So you'd need to handle errors anyway.
Broadly speaking, there are three ways to handle this situation with a single query (fewer queries is usually a good thing to shoot for), but none of them is a universal "best way". Which you should use depends on your needs.
The first is, as you mention, running the INSERT … blindly and handling any errors PHP. This is the best approach when a duplicate key indicates a procedural problem (a bug in the software, a user trying to register a name that's already been used, etc.), as it allows you to perform additional operations before committing to a database update.
Second, there is the INSERT IGNORE … syntax. I would tend to call this the least commonly-useful approach, as it discards your INSERT completely if the key already exists. Primarily useful when a row (or rows) may or may not have been added to the table previously, but the data is known not to have changed.
Lastly, you can use an INSERT … ON DUPLICATE KEY UPDATE … statement. These can get rather verbose, but are very handy, as they allow you to insert data into your table without worrying about whether older data exists. If so, the existing row is updated. If not, a new one is inserted. Either way, your table will have the latest data available.
MySQL supports insert ignore if you want to ignore an insert that creates a row that has a key value that already exists for another row.
Just make sure there's a unique index on email in tblUser and do
$mysqli->query('INSERT IGNORE INTO tblUser ...');
It depends on if you want to ensure that the values you are inserting don't exist or not. If you have a unique key on the file then it is going to be important that you do not create a duplicate key (which will throw an error). A lot of times too you want to test to see if a record exists, if so returning the primary key of the record so you can update the record and if not then inserting the record.
But if you have no unique keys and don't care if information is duplicated across a field or combination of fields then it isn't necessary and can save a little time. It just depends on the situation.
HTH
Often depends on what rules about data duplication apply.
In your example, does your app permit more than one user to have the same email address? If not then you'd need to perform that check.
You definitely want to test first and you may want to test a few things so you can tell the user what went wrong.
For example I just finished a job where a user needed a unique username and a unique email address.