INSERT IGNORE Inserting 0 rows - mysql

When I am attempting to run "INSERT IGNORE ..." in MYSQL to add only one variable to a table of several options, after the first insert, it refuses to work. It says "Inserted rows: 0" and doesn't insert my new value into the database. I believe this is because there is already an entry with a "nothing" value and MYSQL doesn't allow the empty field to be duplicated. This seems to be odd behavior (as long as the two inserts are not exactly the same), so I am wondering if there is some way to avoid this.

The two INSERT do not have to be exactly the same, they just have to be the same for the primary key columns.
INSERT IGNORE will ignore an insert if there is already a row with the same primary key.
If you did INSERT instead of INSERT IGNORE, you would be getting an error (duplicate primary key).
If you want to instead update the existing row, you can use REPLACE.
Either way, there can be only one row for each primary key.

Related

Unique VS INSERT IGNORE

As you know, unique columns only accept non-repetitive values. Now, I saw a keyword named IGNORE (It is used after INSERT statement).
Well, I read about INSERT IGNORE in the documentation and I figured out its job is exactly what unique does! So, when should I use IGNORE instead of unique column? When it is useful?
These two constructs are complimentary. A unique constraint makes sure a column cannot get repetitive values. The ignore keyword in an insert statement allows the insert statement to ignore any errors (such as unique constraint violations) when inserting new rows to a table.
Without the constraint, your insert statement would just create repetitive values in the table. Without the ignore keyword, attempting to insert such values would error out instead of just silently doing nothing.

REPLACE INTO, does it re-use the PRIMARY KEY?

The REPLACE INTO function in MySQL works in such a way that it deletes and inserts the row. In my table, the primary key (id) is auto-incremented, so I was expecting it to delete and then insert a table with id at the tail of the database.
However, it does the unexpected and inserts it with the same id! Is this the expected behaviour, or am I missing something here? (I am not setting the id when calling the REPLACE INTO statement)
This is an expected behavior if you have another UNIQUE index in your table which you must have otherwise it would add the row as you would expect. See the documentation:
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted. See Section 13.2.5, “INSERT Syntax”.
https://dev.mysql.com/doc/refman/5.5/en/replace.html
This really also makes lot of sense because how else would mySQL find the row to replace? It could only scan the whole table and that would be time consuming. I created an SQL Fiddle to demonstrate this, please have a look here
That is expected behavior. Technically, in cases where ALL unique keys (not just primary key) on the data to be replaced/inserted are a match to an existing row, MySQL actually deletes your existing row and inserts a new row with the replacement data, using the same values for all the unique keys. So, if you look to see the number of affected rows on such a query you will get 2 affected rows for each replacement and only one for the straight inserts.

How to get the PK of a ignored row in an INSERT IGNORE statement

I have an INSERT statement with an IGNORE option, because I have a unique field in the insert statement, that is not the primary key. I am using the getGeneratedKeys() command on a PreparedStatement object to get the keys of newly generated rows. Is it possible to configure JDBC in a way so that it returns the id of the ignored row in the case of a query where the IGNORE triggers?
The answer mysql - after insert ignore get primary key seems to indicate that a multi-step workaround is required to retrieve the details of the ignored rows.
With the optional alternative of using REPLACE INTO if you can afford the additional overhead of replacing the rows rather than ignoring them.

INSERT IGNORE increases auto increment counter even no record is added?

In MySQL I used INSERT IGNORE statement to insert rows to table. Because one column is UNIQUE, some rows were not inserted (as they already been there). After execution of that statement I noticed that auto increment column has some missing numbers between rows, which later I realized that happened due to rows that was ignored and not added.
Is it possible to setup system to not increase auto increment counter if no row is inserted with IGNORE clause?
Quoting from the manual page for INSERT:
If you use the IGNORE keyword, errors that occur while executing the
INSERT statement are treated as warnings instead. For example, without
IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY
value in the table causes a duplicate-key error and the statement is
aborted. With IGNORE, the row still is not inserted, but no error is
issued.
The INSERT IGNORE syntax is just a way to suppress certain error messages and it's helpful when you are aware that those errors might happen and/or want to handle them at a later stage. Behind the scenes, you still have a regular insert, except that it fails due to a violated key. MySQL needs the actual row values to make an insert and the AUTO_INCREMENT counter will increment according to regular rules:
The value for the column is NULL.
The value for the column is not set.
The value for the column is greater than the counter.
So unless you can rethink your logic (e.g., test whether the key values exist before making the insert), the only way to reset the counter is ALTER TABLE:
ALTER TABLE t2 AUTO_INCREMENT = value;
It is not that gaps should matter anyway. If they do (e.g., you're generating invoice numbers that need to be correlative), you're probably using the wrong tool for the job.

Is inserting a new database entry faster than checking if the entry exists first?

I was once told that it is faster to just run an insert and let the insert fail than to check if a database entry exists and then inserting if it is missing.
I was also told that that most databases are heavily optimized for reading reading rather than writing, so wouldn't a quick check be faster than a slow insert?
Is this a question of the expected number of collisions? (IE it's faster to insert only if there is a low chance of the entry already existing.) Does it depend on the database type I am running? And for that matter, is it bad practice to have a method that is going to be constantly adding insert errors to my error log?
Thanks.
If the insert is going to fail because of an index violation, it will be at most marginally slower than a check that the record exists. (Both require checking whether the index contains the value.) If the insert is going to succeed, then issuing two queries is significantly slower than issuing one.
You can use INSERT IGNORE so that if the key already exist, the insert command would just be ignored, else the new row will be inserted. This way you need to issue a single query, which checks the duplicate values as well inserts new values too.
still Be careful with INSERT IGNORE as it turns EVERY error into a warning. Read this post for insert ignore
On duplicate key ignore?
I think INSERT IGNORE INTO .... can be used here, either it will insert or ignore it.
If you use the IGNORE keyword, errors that occur while executing the INSERT statement are treated as warnings instead. For example, without IGNORE, a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row still is not inserted, but no error is issued.
If you want to delete the old value and insert a new value you can use REPLACE You can use REPLACE instead of INSERT to overwrite old rows.
REPLACE works exactly like INSERT, except that if an old row in the table has the same value as a new row for a PRIMARY KEY or a UNIQUE index, the old row is deleted before the new row is inserted.
Else use the INSERT IGNORE as it will either inserts or ignores.
a row that duplicates an existing UNIQUE index or PRIMARY KEY value in the table causes a duplicate-key error and the statement is aborted. With IGNORE, the row still is not inserted, but no error is issued.
If your intension is to Insert if its a new record OR Update the record if it already exists then how about doing an UPSERT?
Check out - http://vadivel.blogspot.com/2011/09/upsert-insert-and-update-in-sql-server.html
Instead of checking whether the record exists or not we can try to Update it directly. If there is no matching record then ##RowCount would be 0. Based on that we can Insert it as a new record. [In SQL Server 2008 you can use MERGE concept for this]
EDIT: Please note, I know this works for MS SQL Server and I don't know about MySQL or ORACLE