Mysql - Get auto increment id on actual insert - mysql

Does anyone know if it is possible to get the auto increment id of a field in a mysql table and use it in the same insert?
e.g
assuming the new id here would be 2, an evaluated statement would look as follows
"insert into table (field1) values( 'random-2')"
I know it's possible for me to return this in the code and run another insert, but I wondered if there was a quicker way to 'compute' this during the insert?
1 thought I had was "insert into table (field1) values( 'random' + (select max(id) FROM table) + 1)"
but I'm worried about possible issues with multiple inserts occurring at the same time.
Thanks

It's not possible. You're gonna have to update the entry afterwards.

I'm worried about possible issues with multiple inserts occurring at the same time
That's only part of the problem - insert ids are only suposed to be unique - not contiguous.
If you want to do it in a single call from the application then use a stored procedure to encapsulate the insert+update or use a trigger to fire an update on insert. Or use a sequence generator instead of an autoincrement.

Related

MySQL incrementing Primary Key on INSERT INTO .. ON DUPLICATE KEY UPDATE [duplicate]

Note: I'm new to databases and PHP
I have an order column that is set to auto increment and unique.
In my PHP script, I am using AJAX to get new data but the problem with that is, is that the order skips numbers and is substantially higher thus forcing me to manually update the numbers when the data is inserted. In this case I would end up changing 782 to 38.
$SQL = "INSERT IGNORE INTO `read`(`title`,`url`) VALUES\n ".implode( "\n,",array_reverse( $sql_values ) );
How can I get it to increment +1?
The default auto_increment behavior in MySQL 5.1 and later will "lose" auto-increment values if the INSERT fails. That is, it increments by 1 each time, but doesn't undo an increment if the INSERT fails. It's uncommon to lose ~750 values but not impossible (I consulted for a site that was skipping 1500 for every INSERT that succeeded).
You can change innodb_autoinc_lock_mode=0 to use MySQL 5.0 behavior and avoid losing values in some cases. See http://dev.mysql.com/doc/refman/5.1/en/innodb-auto-increment-handling.html for more details.
Another thing to check is the value of the auto_increment_increment config variable. It's 1 by default, but you may have changed this. Again, very uncommon to set it to something higher than 1 or 2, but possible.
I agree with other commenters, autoinc columns are intended to be unique, but not necessarily consecutive. You probably shouldn't worry about it so much unless you're advancing the autoinc value so rapidly that you could run out of the range of an INT (this has happened to me).
How exactly did you fix it skipping 1500 for ever insert?
The cause of the INSERT failing was that there was another column with a UNIQUE constraint on it, and the INSERT was trying to insert duplicate values in that column. Read the manual page I linked to for details on why this matters.
The fix was to do a SELECT first to check for existence of the value before attempting to INSERT it. This goes against common wisdom, which is to just try the INSERT and handle any duplicate key exception. But in this case, the side-effect of the failed INSERT caused an auto-inc value to be lost. Doing a SELECT first eliminated almost all such exceptions.
But you also have to handle a possible exception, even if you SELECT first. You still have a race condition.
You're right! innodb_autoinc_lock_mode=0 worked like a charm.
In your case, I would want to know why so many inserts are failing. I suspect that like many SQL developers, you aren't checking for success status after you do your INSERTs in your AJAX handler, so you never know that so many of them are failing.
They're probably still failing, you just aren't losing auto-inc id's as a side effect. You should really diagnose why so many fails occur. You could be either generating incomplete data, or running many more transactions than necessary.
After you change 782 in 38 you can reset the autoincrement with ALTER TABLE mytable AUTO_INCREMENT = 39. This way you continue at 39.
However, you should check why your gap is so high and change your design accordingly. Changing the autoincement should not be "default" behaviour.
I know the question has been answered already.. But if you have deleted rows in the table before, mysql will remember the used ID/Number because typically your Auto increment is Unique.. So therefore will not create duplicate increments.. To reindex and increment from the current max ID/integer you could perform:
ALTER TABLE TableName AUTO_INCREMENT=(SELECT max(order) + 1 FROM tablename)
auto increment doesn't care, if you delete some rows - everytime you insert a row, the value is incremented.
If you want a numbering without gaps, don't use auto increment and do it by yourself. You could use something like this to achive this for inserting
INSERT INTO tablename SET
`order` = (SELECT max(`order`) + 1 FROM (SELECT * from tablename) t),
...
and if you delete a row, you have to rearange the order column manually

Incrementing a value in an InnoDB table using MySQL REPLACE

I would like to know if it is possible to use REPLACE MySQL statement in an InnoDB table to see if the key in the table already exists, if it does then increment the value by certain number (for instance 50), else insert a new record with with a certain value (50). Something like this:
REPLACE INTO test(id, NumValue) VALUES (1, NumValue + 50)
This statement doesn't work. It inserts/updates to NULL value. If there is a way to do this using REPLACE statement what is the correct syntax? I know I could do it in couple steps, first using SELECT statement to find out if the record already exists, if it does then do an UPDATE, if it doesn't, then do an INSERT. But I was hoping it could be achieved by using just one step, using REPLACE. And also, I want to avoid using sub-queries.

In MySQL, how can I use the autoincrement value in another column at the time of the INSERT?

I am looking to have the automagically set autoincrement included in another column during the insert. For example in a table where ID is the autoincrement and Name is the other column, I'd like to do something like
`INSERT INTO Names (Name) VALUES (CONCAT("I am number ",ID));`
Currently, I do the INSERT without Name, then I have to immediately after do an UPDATE using $mysqli->insert_id.
I don't want to query the table in advance because, as small a time as it may be, another record could get inserted between getting the next autoincrement value and the insertion. A trigger could work, but it seems like overkill. I just want to know if I can reference the autoincrement within the insertion.
Many thanks!
The problem is not as easy as it seems. In a BEFORE INSERT trigger, the autoincrement value hasn't been generated yet (NEW.autoinc_column is 0), and in an AFTER INSERT trigger, it is not possible anymore to change the values to be inserted.
With MyISAM tables, you could check the table definition for the next AUTO_INCREMENT value:
DELIMITER //
CREATE TRIGGER inserName BEFORE INSERT ON name FOR EACH ROW
BEGIN
DECLARE next_ai INT;
SELECT auto_increment INTO next_ai
FROM information_schema.tables
WHERE table_schema = DATABASE() AND table_name = 'name';
SET NEW.name = CONCAT("I am number ", next_ai);
END //
DELIMITER ;
I believe this could work too with InnoDB tables if innodb_autoinc_lock_mode = 0 (not the case by default), but I am not sure (because of possible concurrency issues).
But if the value to concat is always the same, you probably had better using a view such as:
CREATE VIEW names_v AS SELECT id, CONCAT("I am number ", id) AS name FROM names;
I've also recently been facing this problem and although it might not be the best solution, what I did could be a viable alternative for your case. In my case it was sufficient. You could use a AFTER INSERT trigger to update the field with the value refering to the pseudo-variable NEW. This will probably give you a bit more flexibility.
I needed to fill a field with a string that was computed using the value from the auto increment column.
The trigger reads the NEW pseudo-variable, computes the necessary values and executes the UPDATE.
It still does require two high level write-acesses to the database, but all are done consecutively and without the need for further interaction with the client application (effectively, one single insert statement being sent from the client application, being followed by the implicit update).

MySQL - Split up INSERT in to 2 queries maybe

I have an INSERT query which looks like:
$db->Query("INSERT INTO `surfed` (user, site) VALUES('".$data['id']."', '".$id."')");
Basically I want to insert just like the above query but if the site is already submitted by another user I don't want it to then re-submit the same $id in to the site column. But multiple users can view the same site and all users need to be in the same row as the site that they have viewed which causes the surfed table to have 10s of thousands of inserts which dramatically slows down the site.
Is there any way to maybe split up the insert in some way so that if a site is already submitted it won't then submit it again for another user. Maybe there's a way to use UPDATE so that there isn't an overload of inserts?
Thanks,
I guess the easiest way to do it would be setting up a stored procedure which executes a SELECT to check if the user-site-combination is already in the table. If not, you execute the insert statement. If that combination already exist, you're done and don't execute the insert.
Check out the manual on stored procedures
http://dev.mysql.com/doc/refman/5.1/en/create-procedure.html
You need to set a conditional statement that asks whether the id already exists then if it does update otherwise insert
If you don't need to know whether you actually inserted a line, you can use INSERT IGNORE ....
$db->Query("INSERT IGNORE INTO `surfed` (user, site) VALUES('".$data['id']."', '".$id."')");
But this assumes that you have a unique key defined for the columns.
IGNORE here will ignore the Integrity constraint violation error triggered by attempting to add the same unique key twice.
The MySQL Reference Manual on the INSERT syntax has some informations on that http://dev.mysql.com/doc/refman/5.5/en/insert.html

How to increment the Identity column

I am using identity columns as a primary key in my tables.
In some situations I need to work with primary keys before inserting a new row.
For example, in Oracle I use : select <sequence_name>.nextval into <variable> from dual
and I was sure that no one will insert any row with the same ID while my sp was executing.
As for SQL Server I can read the current identity value and it's increment, but there is no way to increment it without inserting a row.
Updated: The question is - how can I accomplish my task to work with ID (as identity column) in SQL Server before inserting a row and be sure that it will be unique at the end of my stored procedure.
Updated:I have a table with HierarchyId column.The way to form the first level of hierarchy,in my case, is to insert the hierarchyId column, according to indentity column. That is how I'v done it now:
begin transaction
insert into [dbo].[Group](GroupTypeId,CompanyOwnerId,GroupHierarchyId)
values(#GroupTypeId,#HeaderCompanyId,null)
update [dbo].[Group]
set GroupHierarcyId=hierarchyid::GetRoot().GetDescendant(cast ('/'+cast(#NewGroupId as varchar)+'/' as hierarchyid),null)
where GroupId=scope_identity()
commit
You can put an exclusive lock on the table, get the maximum ID, add 1 to it. That will be your next ID. Insert your data, the unlock the table.
HOWEVER,
I cannot fathom why you would want to work with a value before it is created. Can yo post a bit more information on that?
If you need a key that would be unique across databases and database servers, then the GUID's (Global Unique Identifier) certainly fulfills this need.
If you want to generate a new GUID server the you can simply use the NEWID() function
SELECT NEWID()