How to skip duplicates using INSERT INTO in a better optimized way? - mysql

I'd like to build as an experiment a sort of dictionary where any user can suggest new words.
In order to avoid duplicates, I used to do a query SELECT that search for that word and if size is zero then I do the INSERT INTO.
I feel this method works well only if you need to warn the user br lese, but in my case I want something faster and automated and silent.
The very first entry of the word (the very first time a user suggests that word) is going to be the ID of the page word so I don't want to use REPLACE.
I was wondering whether using INSERT IGNORE can be the solution?

INSERT IGNORE will do the trick for you here. You just need to make sure you have a UNIQUE index defined on the column you don't want duplicated.
Another options is INSERT INTO ... ON DUPLICATE KEY UPDATE which won't insert the value again, but will allow you update other columns in that row. A counter or timestamp for example.

"INSERT INTO" to ignore later duplicates, or "INSERT INTO ... ON DUPLICATE KEY UPDATE" to take new fields from the later duplicates: http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Related

auto increment column increments even when there is NO new row insertion

I have created a table which is having a conditional row insertion function,so at times new rows are not inserted into the column. Here the problem is, even when row insertion is failed the auto_inc column increments and thus the values stored in that will be some what like this:
Sl No.
1
2
4
7
8
9
it looks really messy please help.thanks in advance
A sspencer7593 has mentioned
"The behavior of AUTO_INCREMENT is fairly well defined. And it's primarily designed to generate unique values. It's not designed to prevent gaps."
However as MySQL allows you to assign a custom value to AUTO_INCREMENT column a workaround to your scenario would be to assign value of Max(SI_No)+1 while inserting the row. In this case you will ensure that you would add next incremented value only when row is actually inserted.
Typical syntax would look like
INSERT INTO TABLENAME (ID,SOMECOLUMN) VALUES ((SELECT MAX(ID)+1 NEWID FROM TABLENAME) ,someValue);
Note:- it would prevent gaps you are seeing during insertion and last row deletion cases . If you delete row in between you would still see the Gaps but I think this should be OK with you
Can you please add your php code and table structure? I think insert query is being executed even condition fails.
This is expected behavior with INSERT ... SELECT, or when an INSERT statement fails or is rolled back. The innodb_autoinc_lock_mode setting can also influence the behavior. We will also see this when a value is supplied for the AUTO_INCREMENT column, or when rows are deleted.
The behavior of AUTO_INCREMENT is fairly well defined. And it's primarily designed to generate unique values. It's not designed to prevent gaps.
got an answer for this question thanks to # juergen d
this should be the query:
String queryString = "INSERT INTO hcl_candidates(SL_No,candidate,phone,pan,mailid) SELECT MAX(SL_No)+1, ?, ?, ?, ? FROM hcl_candidates";

Copy field into column before Replace Into

I have a database which stores user-published articles. The owner can modify their article at any time.
I do want to add a backup feature, in case the user accidentally deletes the content of their article or something else goes wrong when they update it.
For this reason, I have the content column which stores the content of the article, as well as a backup_content which is intended to keep a copy of the content before the last update.
The user has a "Restore" button which is meant to replace the new content with the backup. Very much like an "Undo" feature.
My prepared statement to insert/update an article is as follows:
REPLACE INTO custom_pages (name, banner_url, full_url, backup_content, content, updated_on) VALUES (?, ?, ?, content, ?, CURRENT_TIMESTAMP);
Here, I tried putting the previous value of content in backup_content and then changing content with the new value. Doing so sets the backup_content to NULL however.
I've seen a few answers on SO on how to achieve a copy, but those answers seem to apply strictly for update and insert, and don't seem to work in Replace queries. I'd prefer one statement over two, and that's where I'm having trouble.
Is there any way to achieve such copy in a single Replace statement?
I would also place my support behind Gordon Linoff's suggestion that you create a continuous update history via triggers and one-to-many related tables.
However, if a significant architectural change is not practical for you right now, you can achieve what you are attempting with INSERT INTO...ON DUPLICATE KEY UPDATE instead of the older REPLACE INTO feature.
Using REPLACE INTO...SELECT FROM may result in more than one access against the table's index, but INSERT INTO...ON DUPLICATE KEY UPDATE should hit it only once.
Since name has a unique index, the presumption is that you never attempt to UPDATE, and instead always execute an INSERT which copies the old value to backup_content.
-- Inserting a row which does not yet exist..
INSERT INTO custom_pages (name, banner_url, full_url, content)
VALUES ('uniquename', 'http://example.com', 'http://example.com', 'this is the original content');
-- In practice, you use this format:
-- uniquename already exists, so update necessary fields
INSERT INTO custom_pages (name, banner_url, full_url, content)
VALUES ('uniquename', 'http://example.com', 'http://example.com', 'this is new content')
ON DUPLICATE KEY UPDATE
-- Update from the VALUES() list
banner_url = VALUES(banner_url),
-- Set backup_content to old content BEFORE updating
-- content from VALUES()
backup_content = content,
content = VALUES(content),
updated_on = NOW();
Using this method, you would never use the first INSERT statement without its ON DUPLICATE KEY clause. Instead, always use the second one; rows that don't exist by unique key will be created, those that already exist will be updated.
Here it is in action: http://sqlfiddle.com/#!9/2f687/1
I think you should re-think your data structure. If you want to preserve history, then use a separate table not column. Something like custom_pages_history. You would remove the backup_content column from your table and instead rely on the history table.
Then, define a trigger on inserts and updates to insert a row into the history table.
The advantages of this approach are:
You have complete history of all the articles.
The changes will be timestamped.
A user can go back to any earlier version of the article, if desired.
This doesn't directly answer your question about replace. Instead of replace you would do an update from the history table.

What is the best way to prevent duplicate values in databases

What is the best way to prevent duplicate values in databases ?
I have a table called names that has only one column called name that is unique (declared as unique attribute).
What is the best way to insert a new name (x) ?
Way1: Should I make a select query for the name x first to check if exist or not. Then make another query to insert the name iff it is not exists in the table.
Way2: Make only one query to insert the name and ignore the error if name already exists.
The second way is the better way. Why run two queries when you can just run one?
When you declare the column as unique, you have told the database to do the extra work for ensure that this is true. You don't need to do anything else -- other than check the errors on the return.
Database constraint will definitely take care about uniqueness, but if you have logic where you need to use last inserted ID to other child table, then only I think you will require to perform manual check before insert, else just ignore exception if raise due to duplication.
The first way works. After the action you can be sure that the record exists (unless some other error occured) You do need a second query (or some another mechanism) to retrieve the actual tuple, either the existing one or a fresly inserted one.
The second way is terrible: the DBMS session is in error-state, {your current work has implicitely been rolled back, and your all cursors have been closed} So, you'll have to start your work allover again, hopefully without the duplicate.
The case you give is a simplified "upsert". Do a search for upsert and you will find answers to the more general question. Some databases, like mysql provide for
insert ignore for this simple case.
Otherwise for the simple case you mention you can use the second approach. For the more general upsert, it is surprisingly difficult to get it right. The issue is concurrent updates. In fact, I have not seen a satisfactory answer for general upserts. Some say to use "merge" but that is subject to concurrency issues.

There is a method in mysql that can INSERT data only if COUNT is equal to zero?

Considering a registration script, i've first to check if an email is already present into the databae.
If it's present no data have to be insert, if not, i can procede with the INSERT INTO
In any case at the end of query i've to know the result for comunicate it at the final user. Acqually i've already done some script, but it requires at least two queries. My goal is to do it with only one query
First you'll want to put a unique key on the e-mail address field. This will prevent you from inserting multiple records with the same e-mail address.
Once you've done that, you can use INSERT IGNORE and checked the number of affected rows returned from the query. If it's zero, you know it was a duplicate. If it's one, then you know it wasn't. Alternatively, you can just use a regular INSERT and catch the duplicate key error generated by the database to know if it was a duplicate record or not.

Replicating a "For Each" loop in a MySQL query

I've been using MySQL at work, but I'm still a bit of a noob at more advanced queries, and often find myself writing lengthy queries that I feel (or hope) could be significantly shortened.
I recently ran into a situation where I need to create X number of new entries in a table for each entry in another table. I also need to copy a value from each row in the second table into each row I'm inserting into the first.
To be clear, here's pseudocode for what I'm attempting to do:
For each row in APPS
create new row in TOKENS
set (CURRENT)TOKENS.APP_ID = (CURRENT)APPS.APP_ID
Any help is appreciated, even if it boils down to "this isn't possible."
As a note, the tables only share this one field, and I'll be setting other fields statically or via other methods, so simply copying isn't really an option.
You don't need a loop, you can use a single INSERT command to insert all rows at once:
INSERT INTO TOKENS (APP_ID)
SELECT APP_ID
FROM APPS;
If you want to set other values for that row, simply modify the INSERT list and SELECT clause. For example:
INSERT INTO TOKENS (APP_ID, static_value, calculated_value)
SELECT APP_ID, 'something', 'calculated-' + APP_ID
FROM APPS