I only want to insert if there are no entries where "name" and "email" exist together.
So it's ok if "name" exists with a different e-mail or vica versa.
mysql_query("INSERT INTO
list (name,email)
VALUES ('$name','$email')
ON DUPLICATE KEY
UPDATE name='$name',email='$email'");
I've made both name & email primary keys but the ON DUPLICATE statement is having no effect.
If name and email is your combined unique key, it makes no sense to trigger the update statement (overwriting with the exact same values) if a dataset already exists. In such a case I would really only INSERT and then check if the database responds with a key constraint violation. This is the expected error that is then ignored. Anything else is still an error.
I wouldn't silence this with this NO-OP update.
You need to have a composite unique key to have ON DUPLICATE KEY UPDATE worked:
CREATE UNIQUE INDEX name_email ON list (name, email);
that is why it called ON DUPLICATE **KEY** UPDATE
Related
I am inserting in multiple tables with foreach loop and I want unique-key column name due to which violating unique key constraints at the run time so i can modify the value and insert it.
foreach ($data as $table_name){
$sql="INSERT INTO $table_name ($column_name) VALUES ($column_vlues)"
$result=query_params($db_conn,$sql,$params)
if($result){
//Do nothing. Its fine
}else{
//If its voileting the unique key contraints then change the column value like new column value = $column_name_which_voileting.$value and then insert it.
}
}
Any help will be appriciated.
You can use pg_get_result_error() to get the PGSQL_DIAG_MESSAGE_PRIMARY, which will contain the constraint name like this:
duplicate key value violates unique constraint "uni_id_key"
From that you can extract the name of the constraint. Then you can query information_schema.constraint_column_usage to find the columns associated with that constraint (if the constraint spans multiple columns, you might have to resort to pg_catalog.pg_constraint to find their relative position).
PostgreSQL actually sends the plain constraint name along with the error message, but PHP has no way to extract that error response field.
This is my code:
INSERT INTO titles_production_companies (production_companies_name, production_companies_tmdb_id, title_id)
values
('United Artists', '60','1'),
('Achte Babelsberg Film', '6100','1'),
('Metro-Goldwyn-Mayer (MGM)', '8411','1'),
('Bad Hat Harry Productions', '9168','1')
ON DUPLICATE KEY UPDATE
title_id=LAST_INSERT_ID(title_id),
production_companies_name='United Artists',
production_companies_tmdb_id='60',
title_id='1',
production_companies_name='Achte Babelsberg Film',
production_companies_tmdb_id='6100',
title_id='1',
production_companies_name='Metro-Goldwyn-Mayer (MGM)',
production_companies_tmdb_id='8411',
title_id='1',
production_companies_name='Bad Hat Harry Productions',
production_companies_tmdb_id='9168', title_id='1';
and I've got this message:
Integrity constraint violation: 1062 Duplicate entry '1-Bad Hat Harry
Productions-9168' for key 'uc_production_companies''
The answer in your situation is likely more related to your (My?)SQL server than to PHP.
Let's think of the steps your code is instructed to execute:
Run a INSERT statement
Check if there is any duplicate key in the statement
If duplicate key is detected, fill some of the fields with the given (fixed) values.
Now, if you have a UNIQUE index on any of the fields you fill in by your ON DUPLICATE clause, this will most likely be duplicated on any triggered duplicate INSERT statement.
Looking at your example, it seems you have an index of UNIQUE on your
production_companies_name column which is violated on all ON DUPLICATE triggers, so only the first would work and all the rest will throw out this error.
Possible solutions:
Remove the UNIQUE type index from the production_companies_name column, if any.
Do not attempt to fill in any UNIQUE index with static values.
Do not attempt to fill in any UNIQUE index at all.
Let me know if that helps :-)
$sql_career = "REPLACE INTO career
(id, battletag, lastHeroPlayed, lastUpdated, monsters, elites, hardcoreMonsters, barbarian, crusader, demonhunter, monk, witchdoctor, wizard, paragonLevel, paragonLevelHardcore)
VALUES
('', '$battletag', '$lastHeroPlayed', '$lastUpdated', '$monsters', '$elites', '$hardcoreMonsters', '$barbarian', '$crusader', '$demonhunter', '$monk', '$witchdoctor', '$wizard', '$paragonLevel', '$paragonLevelHardcore')";
ID auto increments.
battletag is unique.
Everything else changes over time. So I want to replace or update an entry if the battletag already exists without it making a new id. If it doesnt exist I want it to make a new entry letting the id auto increment for that unique battletag.
This works with one problem:
$sql_career = "
insert INTO career
(id, battletag, lastHeroPlayed)
VALUES
(NULL, '$battletag', $lastHeroPlayed)
on duplicate key
update lastHeroPlayed=$lastHeroPlayed;
";
If I, for instance, load in two unique rows, the ID auto increments to 1 and then 2 for each. Then if I load up a row that has a duplicate of the unique key of one of the existing rows (and it then updates as it should) this actually triggers the auto increment. So if I then add in a third unique row, its number will be 4 instead of 3.
How can I fix this?
You want to use the on duplicate key ... update syntax instead of replace into.
Define a unique column (primary or unique index) then check it in your statement like this:
INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
The benefit of using this over a replace into is that replace into will always delete the data you have already and replace it (sort of as the command name implies) with the data that you are supplying the second time round. An update on... statement however will only update the columns you define in the second part of it - if the duplicate is found - so you can keep information in the columns you want to keep it in.
Basically your command will look something like this (Abbreviated for important columns only)
$sql_career = "
insert INTO career
(id, battletag, heroesKilled)
VALUES
($id, '$battletag', $heroesKilled)
on duplicate key
update heroesKilled=heroesKilled+1;
";
Again, remember that in your table, you will need to enforce a unique column on battletag - either a primary key or unique index. You can do this once via code or via something like phpMyAdmin if you have that installed.
Edit: Okay, I potentially found a little gem (it's about a third of the way down the page) that might do the trick - never used it myself though, but can you try the following for me?
$sql_career = "
insert ignore INTO career
(id, battletag, heroesKilled)
VALUES
(null, '$battletag', $heroesKilled)
on duplicate key
update heroesKilled=heroesKilled+1;
";
There seems to be collaborating evidence supporting this in this page of the docs as well:
If you use INSERT IGNORE and the row is ignored, the AUTO_INCREMENT counter is not incremented and LAST_INSERT_ID() returns 0, which reflects that no row was inserted.
I've always used the method of checking a table to see if a row exists, and then update it with my new data or insert it if it doesn't exist, but it's got me thinking what would be wrong with simply doing an update, if no rows are affected, then do an insert statement, that could potentially speed up my script and put less load on the server.
Anyone foresee any problems with this?
What's wrong with REPLACE?
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.
If by "see if a row exists" you mean by primary key, you might be interested by 12.2.5.3. INSERT ... ON DUPLICATE KEY UPDATE Syntax :
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. For
example, if column a is declared as
UNIQUE and contains the value 1, the
following two statements have
identical effect:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;
Maybe you can use this ?
Compared to what you said, tt's doing exactly the other way arround : trying to insert, and if there is a DUPLICATE KEY error, it updates the line... But it allows you not to check if the line exists first.
Still, it only works by primary key / unique index ; not with any kind of where clause.
the REPLACE statement does the same thing, if a row doesn't exist it will insert it, if it exists it will update it.
INSERT IGNORE is also useful here.
Is it possible to insert a row, but only if one of the values already in the table does not exist?
I'm creating a Tell A Friend with referral points for an ecommerce system, where I need to insert the friend's email into the database table, but only if it doesn't already exist in the table. This is because I don't want any more than 1 person getting the referral points once the new customer signs up and purchases something. Therefore I want only one email ever once in the table.
I'm using PHP 4 and MySql 4.1.
This works if you have a unique index or primary key on the column (EmailAddr in this example):
INSERT IGNORE INTO Table (EmailAddr) VALUES ('test#test.com')
Using this if a record with that email already exists (duplicate key violation) instead of an error, the statement just fails and nothing is inserted.
See the MySql docs for more information.
If the column is a primary key or a unique index:
INSERT INTO table (email) VALUES (email_address) ON DUPLICATE KEY UPDATE
email=email_address
Knowing my luck there's a better way of doing it though. AFAIK there's no equivalent of "ON DUPLICATE KEY DO NOTHING" in MySQL. I'm not sure about the email=email_Address bit, you could play about and see if it works without you having to specify an action. As someone states above though, if it has unique constraints on it nothing will happen anyway. And if you want all email addresses in a table to be unique there's no reason to specify it as unique in your column definition.
Most likely something like:
IF NOT EXISTS(SELECT * FROM myTable WHERE Email=#Email) THEN INSERT INTO blah blah
That can be rolled into one database query.
A slight modification/addition to naeblis's answer:
INSERT INTO table (email) VALUES (email_address)
ON DUPLICATE KEY UPDATE id=LAST_INSERT_ID(id)
This way you don't have to throw email=email_address in there and you get the correct value for LAST_INSERT_ID() if the statement updates.
Source: MySQL Docs: 12.2.5.3
MySQL offers REPLACE INTO http://dev.mysql.com/doc/refman/5.0/en/replace.html:
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.
I'm not sure if I got it, but what about a
try {
mysql_query($sql);
}
catch(Exception $e) {
}
combined with an unique field index in MySQL?
if it throws an exception then you know that you got a duplicated field.
Sorry if that don't answer your question..
If the email field was the primary key then the constraints on the table would stop a duplicate from being entered.