How to prevent duplicate inserts into a table - php

I want to insert data into Mysql, and when the data is already in the table, it should not be inserted again. How to prevent the second insert?
try {
$conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
// set the PDO error mode to exception
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "INSERT INTO MyGuests(firstname, lastname, email)
VALUES ('John', 'Doe', 'john#example.com')";
// use exec() because no results are returned
$conn->exec($sql);
echo "Table MyGuests created successfully";
} catch(PDOException $e) {
echo $sql . "<br>" . $e->getMessage();
}
$conn = null;
The result is like this:

You do not have a unique key on the email address. That is your best hope, as many John Doe's can be in the system. So a unique composite index on full name is not ever a good idea.
One can issue an INSERT IGNORE which plods along after a duplicate violation as if nothing happens (this is highly unrecommended, and in your case not possible because your unique constraint on email is not present). The major problem with doing this is that your tend (read: probably will) lose all control of flow of what is happening and be left with undesired data. So don't use it, unless you are a pro.
One can issue and INSERT ON DUPLICATE KEY UPDATE (a.k.a. IODKU) that also requires a unique key (can be a unique composite too). As such, a new row would not occur but an update to the row. As an example, a new row with 4 columns could be inserted, but on duplication violation, an update could be performed on just two of the columns, such as
assuming in below a PK on an unseen column id int, and a unique key on emailAddr
insert person(firstName,lastName,emailAddr) values 'Joe','Smith','jsmith#email.com'
on duplicate key update firstName='Joe',lastName='Smith'
It is the unique key on emailAddr that makes this work. Left with only 1 row per emailAddr, ever.
So, you can have unlimited Joe Smiths, but only 1 row per email address.
The create table for the above table could look like
create table person
( id int auto_increment primary key,
firstName varchar(50) not null,
lastName varchar(50) not null,
emailAddr varchar(150) not null,
unique key(emailAddr) -- without this, IODKU will not work
);
You can also issue ALTER TABLE commands to add constraints after the table is created. Depending on the data therein, the call may fail.
Mysql Insert on Duplicate Key Update, and Alter Table manual pages.
I will say it again, without the proper schema setup, IODKU will not work and you will be left with undesired rows. So don't be lazy about it. Setup schema first allowing it to success (with unique keys), then move on toward using IODKU.

You need to add a unique constraint/index and ignore errors caused by the duplication. If this is your query:
INSERT INTO MyGuests(firstname, lastname, email)
VALUES ('John', 'Doe', 'john#example.com');
And you want to prevent all three columns from being re-inserted, then you can add the unique as:
create unique index unq_myguests_firstname_lastname_email on myguests(firstname, lastname, email);
Then, phrase the insert as:
INSERT INTO MyGuests(firstname, lastname, email)
VALUES ('John', 'Doe', 'john#example.com')
ON DUPLICATE KEY UPDATE firstname = VALUES(firstname);
The ON DUPLICATE KEY UPDATE portion does nothing, except ignore the errors.

Related

Trying to add two rows in MySQL with the same id

I have a MySQL table that has Auto-increment on the ID field. However I need to create, via php, two rows with the same id.
I've tried using $last_id = intval(mysql_insert_id()); But just can't get to set the id on the second row. I am very new to php and SQL has never been my closest friend.
$sql = "INSERT INTO 'table name' (name, age, phone) VALUES ({$name}, {$age}, {$phone});"
$result = mysqli_query($conn, $sql);
Then I would like to run the same insert statement again, maybe with the phone being different, but with the ID being the same.
Your problem here is the auto_increment ID field. This is a primary key, since any auto_increment field must be defined as the table's primary key and therefore cannot have duplicate records.
What you could do is create and additional field for your "ID" field that you want to duplicate and then you can insert normally and leave the auto incrementing field do it's thing.

Insert or update (if exists) without primary key

I have the following database MySQL table.
id (PK, AI)
email
country
lastlogin
I have a regular query in PHP that inserts this into the table.
however, logically, if this code runs several times, the same row will be inserted to the database every time.
I want my reference for checking and duplication to be the email field, and if the email is the same, update the country and the lastlogin.
I checked on other questions for a similar issue and the suggested way was to use ON DUPLICATE KEY like this
INSERT INTO <table> (field1, field2, field3, ...)
VALUES ('value1', 'value2','value3', ...)
ON DUPLICATE KEY UPDATE
field1='value1', field2='value2', field3='value3', ...
However, my primary key is not the email field rather the id but I don't want to run the check on it.
One option is make the email field unique, and then it should behave the same as primary key, at least with regard to MySQL's ON DUPLICATE KEY UPDATE:
ALTER TABLE yourTable ADD UNIQUE INDEX `idx_email` (`email`);
and then:
INSERT INTO yourTable (email, country, lastlogin)
VALUES ('tony9099#stackoverflow.com', 'value2', 'value3')
ON DUPLICATE KEY UPDATE
email='value1', country='value2', lastlogin='value3'
If the email tony9099#stackoverflow.com already exists in your table, then the update would kick in with alternative values.
From the MySQL documentation:
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, MySQL performs an UPDATE of the old row.
This approach doesn't only work with primary keys, it also works with any column having a unique index.
As Dan has mentioned, the ROW_COUNT() in-built function does not support this solution with a standard configuration.
MySQL::ROW_COUNT()
For UPDATE statements, the affected-rows value by default is the number of rows actually changed. If you specify the CLIENT_FOUND_ROWS flag to mysql_real_connect() when connecting to mysqld, the affected-rows value is the number of rows “found”; that is, matched by the WHERE clause.
If modifying the database schema is not an option, you could use the following method:
UPDATE `table` SET `country`='value1', `lastlogin`='value1' WHERE `email`='value3'
IF ROW_COUNT()=0
INSERT INTO `table` (`email`, `country`, `lastlogin`) VALUES ('value1', 'value2', 'value3')
you can use
$query=mysql_query("select * from table where email = 'your email'");
if(mysql_num_rows($query) > 0){
//update
}else{
//insert
}
You can load a row with the given email first and then decide if you have to insert or update depending on the existence of the loaded row. This needs multiple SQL statements, but it can be written in a DBMS vendor independent way. Use a surrounding transaction to handle concurrency. An index on the email-column is useful to keep the existence - check fast. Adding a unique - constraint on the email-column is an option to guarantee that there will never be multiple rows with same email.
You can do it manually like before inserting the value to table first check whether the value exists in table or not if yes then update your related field
$qry = mysql_query("select * from table where email='abc#abc.com'");
$count = mysql_num_rows($qry);
if($count > 0){
write your update query here
}else{
write your insert query here
}

Preventing duplicate rows in mysql db, IGNORE not working

I am trying to prevent the insertion of duplicate rows into mysql database. The table name is favorites and I have two columns in my table: company_id and user_id, I want to prevent users to try to add the same company to the db as a 'favorite' twice.
This is what I tried:
$query = "INSERT IGNORE INTO favorites (item_id, user_id) VALUES ( $item_id, $user_id )";
mysql_query($query,$conn);
But does not work.
I also tried to 'alter table' to add a primary key, however, I need both user_id and item_id to be keys, because the same favorited item can be favorited by more than one 'user_id' and the same 'user_id' can insert many different favorited items, so that data can be 'duplicated' but I am trying to prevent the exact same 'user_id' and 'item_id' to be inserted twice.
I appreciate any help with this.
The easiest way I know of is to add a UNIQUE constraint on the user_id-item_id pair, which would be accomplished with the following query:
ALTER TABLE favorites
ADD UNIQUE(item_id,user_id)
Your insert query would then return an error whenever you tried to insert a user_id-item_id pair that already existed in your table, so your INSERT query should be modified thusly:
INSERT INTO favorites(item_id,user_id)
VALUES ($item_id,$user_id)
ON DUPLICATE KEY UPDATE item_id=item_id
I do not recommend using "INSERT IGNORE" because it ignores ALL errors. My query will simply set item_id=item_id (no change) whenever it detects a duplicate key, so data will not be duplicated.
I also strongly encourage you to look into using MySQLi instead of the mysql_* functions. The PHP that you posted is very susceptible to mysql injections should you forget to check those two user input variables. Even the PHP manual actively discourages those functions for the same reason.
You can use a composite primary key of the columns like so:
ALTER TABLE table ADD PRIMARY KEY ( 'item_id' , 'user_id' )
This means that same user_ids and item_ids are allowed and only a combination of them needs to be unique.
Try adding a composite primary key (from item_id and user_id) to the table.
You will get an error if you already have data in your table that would violate this constraint, in this case you will need to create a new table and migrate your data into the new table.
INSERT IGNORE only works on keys. Typically the only key you have is the primary key on a table.
So, first search for matching rows and if they exist, don't insert a new record.
$search_q = "SELECT `id` FROM `favorites` WHERE `item_id` = ";
$search_q .= mysql_real_escape_string($item_id);
$search_q .= " AND `user_id` = ";
$search_q .= mysql_real_escape_string($user_id);
$r = mysql_query($search_q);
if (!mysql_num_rows($r)) {
# This combination doesn't exist
$insert_q = "INSERT INTO `favorites` (`item_id`,`user_id`) VALUES (";
$insert_q .= mysql_real_escape_string($item_id).",";
$insert_q .= mysql_real_escape_string($user_id).")"
mysql_query($insert_q);
}

On Duplicate Key Update (Non unique field)

I'm working on a CSV import script in PHP attached to a MySQL database. I want to give the users the option to either insert new rows if duplicates are found or update them.
I can't use ON DUPLICATE KEY UPDATE because the column cannot be unique, otherwise it won't cater for when they want to have duplicates.
How would I go about this?
Use 2 queries - a select query to determine if the row exists, then based on that result either an insert or update query.
I would script it for use on the command line. In your loop, check if an entry with the same key already exists. If it does, prompt the user to decide what to do using fgets(STDIN).
why not just add a UNIQUE key to the table, possibly spanning multiple fields?
here is an example given the following simple phonebook table:
CREATE TABLE phonebook (
firstname VARCHAR(255),
lastname VARCHAR(255),
home VARCHAR(50),
mobile VARCHAR(50)
)
you can easily add a key making firstname AND lastname together unique.
ALTER TABLE phonebook ADD UNIQUE (firstname, lastname)
that way you can use the ON DUPLICATE KEY UPDATE statement to easily update the phone numbers when the name is already on the list:
INSERT INTO phonebook (firstname, lastname, home, mobile)
VALUES ("john", "doe", "12345", "45678")
ON DUPLICATE KEY UPDATE home = "12345", mobile = "45678"
everything else is getting unnecessarily complex.

Why can't I insert the same ID into the 'id' column of my MySQL table?

I'm creating a messaging system and I'm trying to set it up so it will have a "conversation view" and so users can reply to a message. To do this I have to have a primary ID for each conversation in the table and then a separate unique ID for each message.
My problem is that when I try replying to a message I get this error:
Duplicate entry '98' for key 1
It looks like it isn't allowing me to use the same ID in a column, but I don't have a 'unique' thing set in the table AFAIK.
I also tried to drop the PRIMARY for the id column but got this error:
The message is:
#1075 - Incorrect table definition; there can be only one auto column and it must be defined as a key
I don't understand why it won't let me insert the same ID into the id column, because as you know I need an ID for each conversation.
The mysql_query that I'm using to insert the reply into the table is:
$sql = "INSERT INTO messages (id, message_id, to_user, message, subject, from_user, date, time, date_short)
VALUES ('$id', '$message_id', '$to', '$message', '$subject', '$user', '$date', '$time', '$date_short')";
mysql_query($sql) or die(mysql_error());
Thanks in advance!
Your primary key can not be repeated, otherwise it isn't so useful as a key, is it? The primary key must uniquely identify the record.
The reason you're getting the error is that the column is set to be auto-number. You have not added that column to a separate key, which is a requirement for auto-number columns in MySQL.
Add it to a key/index with that column first, then remove the PK attribute. Make sure you have some PK in the table.
You can't have auto_increment without a key
I suspect you have AUTO_INCREMENT setup on your id field. If this is the case, then the values in the id column must be unique.
Either remove the AUTO_INCREMENT attribute on that column (by redefining the column without AUTO_INCREMENT via an ALTER TABLE command), or don't specify the id value in your INSERT statement.
First, untick AUTO_INCREMENT option on your column and as the second step, try to drop the index again
PRIMARY KEYs are also unique. auto_increment columns must be primary keys. You can't drop PRIMARY KEY from a column without making it not auto_increment.
However, I don't think you should change your table like this. You should keep your IDs and either create a new table with the data you need to update, or use UPDATE instead of INSERT.
Columns with primary keys can't have duplicates, otherwise they lose their uniqueness. MySQL will prevent same values. Having to alter primary key vales is also bad news. You may want to re-approach what you're doing and possibly create more tables.

Categories