select and insert if value missing without duplicating primary keys [duplicate] - mysql

Since IF EXISTS isn't supported by MySQL I am struggling to think of the syntax for doing something like the following pseudo in MySQL:
IF ((select count(*) from table where col1='var1' AND col2='var2' AND col3='var3' AND col4='var4' AND col5='var5')>0) then
combination of vars exist in record - do a thing;
ELSE
combination of vars does not exist in record - insert record;
END IF;
I should have thought CASE would suit this but for life of me I'm unable to think of the correct syntax. I'd use unique indexes but every one of the columns needs to allow duplicates, it's only a matching combination of all the columns that needs to be unique, not the fields themselves.
I'm told using a composite key across all the columns would avoid duplicate inserts but from what I gather I need to use a different insert then.
Short version: In MySQL, how do I insert new row only if an exact specified match of columns is not found in an existing row.
Any advice or suggestions would be greatly appreciated.

Create a composite unique index. This will allow any number of duplicates in the individual fields, but the combination needs to be unique.
CREATE UNIQUE INDEX ix_uq ON test (field1, field2, field3);
...and use INSERT IGNORE to insert if the unique index is not violated. If it is, just ignore the insert.
INSERT IGNORE INTO test (field1,field2,field3) VALUES (1,1,1);
An SQLfiddle for testing.
If you want to insert unless there's a duplicate, and update if there is, you can also use INSERT INTO ... ON DUPLICATE KEY UPDATE;
INSERT INTO test (field1, field2, field3) VALUES (1,1,1)
ON DUPLICATE KEY UPDATE field4=field4+1;
Another SQLfiddle.

Related

MySQL: Making 2 values unique

I'm trying to make 2 values unique, like if I have the values (5, 10) the same values can't be added again.
I'm currently selecting from the table the values x and y, checking if they both together exists on the table if they don't exists insert them, in other words
"Select * from location where x=? and y=?"
if no result is returned it will continue to insert the values.
This is typically accomplished by creating a unique index on both columns combined (a multi-column index).
Then, MySQL will prevent you from inserting duplicates. You can go ahead and try to insert the record, and if you get a duplicate key error, you know it already exists.
Alternatively, another way to handle it is to use INSERT IGNORE, so that no error occurs if you try to insert a duplicate row. Still, it won't insert, so you simply check the affected ROW_COUNT() to see if the insert was successful.
Using a unique index and catching the failure on the insert is more performant than selecting then trying to insert because in the case you do insert, MySQL only has to perform one search, rather than two.

How to get around duplicates when inserting multiple values for many to many relationship - mysql

Adding keywords to db.
I have 3 tables.
Articles
-ArticleID PK
-ArticleTitle
-ArticleBody
Keywords
-KeywordID PK
-Keyword UNIQUE
Keyword_Article
-KeywordID PK
-ArticleID
Trying to figure out how to update the Keyword tables as efficiently as possible.
All I have is SQLBUDDY to work with for now.
I have had success with
INSERT INTO Keywords (KeywordID, Keyword)
VALUES (NULL,'test');
INSERT INTO Keyword_Article (KeywordID, ArticleID)
VALUES ('LAST_INSERT_ID()','2222');
But when I run into a keyword that already exists this obviously does not work.
Im guessing a need an if/else/then or is there some other way that this should be done.
I have read about stored procedures which could help stop the second table from populating if the first one fails but I cant seem to get them to work in SQLBUDDY.
eg.
BEGIN
INSERT INTO Keywords (KeywordID, Keyword)
VALUES (NULL,'test')
INSERT INTO Keyword_Article (KeywordID, ArticleID)
VALUES ('LAST_INSERT_ID()','2222');
COMMIT;
Keeps giving errors.
What is the best way to do this kind of multiple insert?
You can do something like this:
INSERT IGNORE INTO Keywords (Keyword)
VALUES ('test')
INSERT INTO Keyword_Article (KeywordID, ArticleID)
VALUES ((SELECT KeywordID FROM Keywords WHERE Keyword = 'test'),'2222');
That will try to insert a new keyword, but ignore it if it already exists. The second query will always find the KeywordID whether it is new or not.
You can do it like this:
-- Forces Keyword to be unique
CREATE UNIQUE INDEX Keywords_ndx ON Keywords(Keyword);
and then:
-- Inserts keyword into Keywords, failing silently if duplicated
INSERT IGNORE INTO `Keywords` (`Keyword`) VALUES ('test');
-- Retrieves that keyword's ID, be it newly inserted or duplicated.
INSERT IGNORE INTO Keyword_Article (KeywordID, ArticleID)
SELECT KeywordID, 2222 FROM Keywords WHERE Keyword='test';
Keyword_Article has both fields as primary key. You declared only KeywordID as PK, but that way, you cannot have two articles with the same keyword, which seems strange and may lead to undesired behaviour.

insert on duplicate key update

I would like to use "insert on duplicate key update" in a query to either insert a new row if it does not exist or update a row if it does. What I can not seem to figure out is how to use this if I do not have the unique id (because the row has not yet been created, and this ID will be autoincremented upon insert)
insert into foodchoices (unique,notunique) values (Idonthavethis,'test')
on duplicate key update notunique = 'stuff';
Now, in this example above, where it says "Idonthavethis", I do not have any unique value for this field, because it has not yet been inserted as a row. However, I do expect that this inserts somehow, I just dont know how. I expect it to act like this:
insert into foodchoices (notunique) values ('test')
BUT, if it is a field that does already exist, I WILL have that unique value. Is there some form of wildcard or something I can use for when I do not have the unique value?
I believe the answer to this is addressed in the MySQL docs:
If a table contains an AUTO_INCREMENT column and INSERT ... UPDATE inserts a row, the LAST_INSERT_ID() function returns the AUTO_INCREMENT value. If the statement updates a row instead, LAST_INSERT_ID() is not meaningful. However, you can work around this by using LAST_INSERT_ID(expr). Suppose that id is the AUTO_INCREMENT column. To make LAST_INSERT_ID() meaningful for updates, insert rows as follows:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id), c=3;
I think what you just might try to do is select the row with the value you have (if exists then update) otherwise insert. It's just one more sentence.
I just don't see how can you compare an existing value that you just don't have (the generated ID). Plus, if the ID is DB seeded how it'll be duplicated?
May be you need to alter your table structure for adding any constraint to "notunique" column. So you can:
insert into foodchoices (notunique) values ('test') on duplicate key update columntostoreyouruniqueid = unique;
if notunique has no constaint then it mean that you will have uniqueid as set. So it has to double query.

SQL Upon finding duplicate key, replace entire entry

I have an insert query for MySQL that looks like this:
INSERT INTO table (foo, bar, fooo, baar, etc) VALUES (?,?,?,?,?)
It is used in a script to migrate some columns and keeps encountering duplicate primary keys. (Old database was awful and poorly maintained).
Is there a way I can just tell it to replace the whole offending row with the current values tossing out the old stuff entirely? I know there is an ON DUPLICATE KEY UPDATE command, but I don't know if it would help me as all I've seen it used for is incrementing.
ANSWER: INSERT INTO table (foo, bar, fooo, baar, etc) VALUES (?,?,?,?,?) ON DUPLICATE KEY UPDATE foo=?, bar=?, fooo=?, baar=?, etc=?
Keep in mind that you have to add the values in the referenced array again to account for the extra question marks.
on duplicate key update should work, as should a replace statement.
From MySQL manual:
If you specify ON DUPLICATE KEY
UPDATE, and a row is inserted that
would cause a duplicate value in a
UNIQUE index or PRIMARY KEY, an UPDATE
of the old row is performed.
What you said:
Is there a way I can just tell it to
replace the whole offending row with
the current values tossing out the old
stuff entirely?
Conclusion: why don't you just try it? It seems it does exactly what you want.
Edit: Since you haven't provided any examples of what you were trying to do, I'll use some from MySQL's website.
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
Or if you want something that relates more to real world:
INSERT INTO table(int_field, str_field, float_field) VALUES (15, 'some string', '1.22')
ON DUPLICATE KEY UPDATE int_field = 15, str_field = 'some_string', float_field = '1.22';

Create if an entry if it doesn't exist, otherwise update?

Kinda strange to put it into words that short, heh.
Anyway, what I want is basically to update an entry in a table if it does exist, otherwise to create a new one filling it with the same data.
I know that's easy, but I'm relatively new to MySQL in terms of how much I've used it :P
A lot of developers still execute a query to check if a field is present in a table and then execute an insert or update query according to the result of the first query.
Try using the ON DUPLICATE KEY syntax, this is a lot faster and better then executing 2 queries. More info can be found here
INSERT INTO table (a,b,c) VALUES (4,5,6)
ON DUPLICATE KEY UPDATE c=9;
if you want to keep the same value for c you can do an update with the same value
INSERT INTO table (a,b,c) VALUES (4,5,6)
ON DUPLICATE KEY UPDATE c=6;
the difference between 'replace' and 'on duplicate key':
replace: inserts, or deletes and inserts
on duplicate key: inserts or updates
if your table doesn't have a primary key or unique key, the replace doesn't make any sense.
You can also use the VALUES function to avoid having to specify the actual values twice. E.g. instead of
INSERT INTO table (a,b,c) VALUES (4,5,6) ON DUPLICATE KEY UPDATE c=6;
you can use
INSERT INTO table (a,b,c) VALUES (4,5,6) ON DUPLICATE KEY UPDATE c=VALUES(c);
Where VALUES(c) will evaluate to the value specified prevously (6).
Use 'REPLACE INTO':
REPLACE INTO table SET id = 42, foo = 'bar';
See more in the MySQL documentation
As the others have said, REPLACE is the way to go. Just be careful using it though, since it actually does a DELETE and INSERT on the table. This is fine most of the time, but if you have foreign keys with constraints like ON DELETE CASCADE, it can cause some big problems.
Look up REPLACE in the MySQL manual.
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 12.2.5, “INSERT
Syntax”.
REPLACE is a MySQL extension to the
SQL standard. It either inserts, or
deletes and inserts. For another MySQL
extension to standard SQL — that
either inserts or updates — see
Section 12.2.5.3, “INSERT ... ON
DUPLICATE KEY UPDATE Syntax”.
If you have the following INSERT query:
INSERT INTO table (id, field1, field2) VALUES (1, 23, 24)
This is the REPLACE query you should run:
REPLACE INTO table (id, field1, field2) VALUES (1, 23, 24)