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
}
Related
How would I reset the primary key counter on a sql table and update each row with a new primary key?
I would add another column to the table first, populate that with the new PK.
Then I'd use update statements to update the new fk fields in all related tables.
Then you can drop the old PK and old fk fields.
EDIT: Yes, as Ian says you will have to drop and then recreate all foreign key constraints.
Not sure which DBMS you're using but if it happens to be SQL Server:
SET IDENTITY_INSERT [MyTable] ON
allows you to update/insert the primary key column. Then when you are done updating the keys (you could use a CURSOR for this if the logic is complicated)
SET IDENTITY_INSERT [MyTable] OFF
Hope that helps!
This may or not be MS SQL specific, but:
TRUNCATE TABLE resets the identity counter, so one way to do this quick and dirty would be to
1) Do a Backup
2) Copy table contents to temp table:
3) Copy temp table contents back to table (which has the identity column):
SELECT Field1, Field2 INTO #MyTable FROM MyTable
TRUNCATE TABLE MyTable
INSERT INTO MyTable
(Field1, Field2)
SELECT Field1, Field2 FROM #MyTable
SELECT * FROM MyTable
-----------------------------------
ID Field1 Field2
1 Value1 Value2
Why would you even bother? The whole point of counter-based "identity" primary keys is that the numbers are arbitrary and meaningless.
you could do it in the following steps:
create copy of yourTable with extra column new_key
populate copyOfYourTable with the affected rows from yourTable along with desired values of new_key
temporarily disable constraints
update all related tables to point to the value of new_key instead of the old_key
delete affected rows from yourTable
SET IDENTITY_INSERT [yourTable] ON
insert affected rows again with the new proper value of the key (from copy table)
SET IDENTITY_INSERT [yourTable] OFF
reseed identity
re-enable constraints
delete the copyOfYourtable
But as others said all that work is not needed.
I tend to look at the identity type primary keys as if they were equivalent of pointers in C, I use them to reference other objects but never modify of access them explicitly
If this is Microsoft's SQL Server, one thing you could do is use the [dbcc checkident](http://msdn.microsoft.com/en-us/library/ms176057(SQL.90).aspx)
Assume you have a single table that you want to move around data within along with renumbering the primary keys. For the example, the name of the table is ErrorCode. It has two fields, ErrorCodeID (which is the primary key) and a Description.
Example Code Using dbcc checkident
-- Reset the primary key counter
dbcc checkident(ErrorCode, reseed, 7000)
-- Move all rows greater than 8000 to the 7000 range
insert into ErrorCode
select Description from ErrorCode where ErrorCodeID >= 8000
-- Delete the old rows
delete ErrorCode where ErrorCodeID >= 8000
-- Reset the primary key counter
dbcc checkident(ErrorCode, reseed, 8000)
With this example, you'll effectively be moving all rows to a different primary key and then resetting so the next insert takes on an 8000 ID.
Hope this helps a bit!
I have 2 similar tables. One with an auto increment value and one without. The first table first column is defined as INT(11), PRIMARY UNIQUE INDEX and under EXTRA in phpmyadmin it says AUTO_INCREMENT.
This code does not work and does not add any values.
mysqli_query($con, "INSERT INTO testtable1 VALUES ('', 'zzz', 'yyy')") ;
The second table is the same table with the first column dropped. This code works.
mysqli_query($con, "INSERT INTO testtable2 VALUES ('jjj', 'fff')") ;
Any idea what I am missing? Running 7.2 on the database.
Presumably your testtable1 has a definition reasonably similar to (pseudo-notation):
testtable1
------------
ID INT PK AUTOINCREMENT
SomeColumn NVARCHAR
AnotherColumn NVARCHAR
So when you do this:
INSERT INTO testtable1 VALUES ('', 'zzz', 'yyy')
You're explicitly telling the database to insert an empty string into an INT column. Which won't work.
An AUTOINCREMENT column doesn't need to be told there's an empty value, it will automatically increment. Just specify the values that you are inserting:
INSERT INTO testtable1 (SomeColumn, AnotherColumn) VALUES ('zzz', 'yyy')
Let the database engine handle the ID column. In general it's pretty much always worth explicitly specifying the columns into which you are inserting values or from which you are selecting values. It makes the code easier to read/support and reduces the chance of bugs/errors if the table definition ever slightly changes.
If I am reading this correctly, the first table has an int(11) with AUTO_INCREMENT.
This means you should use similar query as in table 2. As in only pass in values for the two non auto increments fields.
mysqli_query($con, "INSERT INTO testtable1 VALUES ('zzz', 'yyy')") ;
This will work as long as there are 3 fields, the first one is an auto inc int and the other two are strings. This is because auto inc handles the first column automatically.
Also, please check out this link or search for php MySQL predated statements to use prepared statements instead for some safety. It will help you against sql injections.
Here is what I want to do. Insert if the unique index (code) doesn't exist in the table already. If it exists then simply update the row.
I can't use primary key because it is Auto Increment ID. Here is the code
$sql="INSERT INTO codes (code,registration,country)
VALUES ('$war','$regi','$country') ON DUPLICATE KEY UPDATE code='$war', registration='$regi', country='$country'";
But it doesn't work because I think it is checking for duplicate primary key. So when I try to insert the row in which the value of column code is same as previous row I get Duplicate entry 'xxx' for key 'code' error. So how to make this work for unique index code ?
Ahmar
ON DUPLICATE KEY UPDATE works with UNIQUE indexes as well as PRIMARY KEY values. Try setting one of the values you are trying to update to be UNIQUE on your database table.
All you have to do is set code to be a unique index. Then, anytime you try to do an insert where code matches it will update instead.
Alter this code as needed
alter table `table` add unique index(`code`);
You are correct, having a primary key on your table will not allow you to insert duplicate key values.
In the past, I have used something like this:
SELECT COUNT(*)
FROM codes
WHERE code = '$war'
Then if the count is > 0, you know there's a duplicate and you do:
UPDATE codes
SET registration = '$regi', country = '$country'
WHERE code = '$war'
Otherwise you do:
INSERT INTO codes (code, registration, country)
VALUES ('$war', '$regi', '$country')
However, if we assume you're using MySQL, you might be able to make use of either INSERT IGNORE or REPLACE.
If you use:
INSERT IGNORE codes (code, registration, country)
VALUES ('$war', '$regi', '$country')
The values will be inserted if the code does not already exist. If the code does exist, no record is inserted and MySQL will silently discard the statement without generating an error.
I think what you probably want is this:
REPLACE INTO codes (code, registration, country)
VALUES ('$war', '$regi', '$country')
REPLACE INTO behaves just like INSERT INTO if the record is new. But if the primary key is duplicated, it will perform an UPDATE instead.
Again, INSERT IGNORE and REPLACE INTO are for MySQL only.
Reference: http://www.tutorialspoint.com/mysql/mysql-handling-duplicates.htm
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);
}
This question already has answers here:
MySQL 'UPDATE ON DUPLICATE KEY' without a unique column?
(3 answers)
Closed 10 months ago.
I'm trying to create more robust MySQL Queries and learn in the process. Currently I'm having a hard time trying to grasp the ON DUPLICATE KEY syntax and possible uses.
I have an INSERT Query that I want to INSERT only if there is no record with the same ID and name, otherwise UPDATE. ID and name are not UNIQUE but ID is indexed.ID isn't UNIQUE because it references another record from another table and I want to have multiple records in this table that reference that one specific record from the other table.
How can I use ON DUPLICATE KEY to INSERT only if there is no record with that ID and name already set else UPDATE that record?
I can easily achieve this with a couple of QUERIES and then have PHP do the IF ELSE part, but I want to know how to LIMIT the amount of QUERIES I send to MySQL.
UPDATE: Note you need to use IF EXISTS instead of IS NULL as indicated in the original answer.
Code to create stored procedure to encapsulate all logic and check if Flavours exist:
DELIMITER //
DROP PROCEDURE `GetFlavour`//
CREATE PROCEDURE `GetFlavour`(`FlavourID` INT, `FlavourName` VARCHAR(20))
BEGIN
IF EXISTS (SELECT * FROM Flavours WHERE ID = FlavourID) THEN
UPDATE Flavours SET ID = FlavourID;
ELSE
INSERT INTO Flavours (ID, Name) VALUES (FlavourID, FlavourName);
END IF;
END //
DELIMITER ;
ORIGINAL:
You could use this code. It will check for the existence of a particular record, and if the recordset is NULL, then it will go through and insert the new record for you.
IF (SELECT * FROM `TableName` WHERE `ID` = 2342 AND `Name` = 'abc') IS NULL THEN
INSERT INTO `TableName` (`ID`, `Name`) VALUES ('2342', 'abc');
ELSE UPDATE `TableName` SET `Name` = 'xyz' WHERE `ID` = '2342';
END IF;
I'm a little rusty on my MySQL syntax, but that code should at least get you most of the way there, rather than using ON DUPLICATE KEY.
id and name are not unique but id is
indexed. id isn't unique
How can I use ON DUPLICATE KEY to
INSERT only if there is no record with
that id and name already set else
UPDATE that record?
You can't. ON DUPLICATE KEY UPDATE needs a unique or primary key to determine which row to update. You are better off having PHP do the IF ELSE part.
edit:
If the combination of name and id IS supposed to be unique, you can create a multi-column UNIQUE index. From there you can use ON DUPLICATE KEY UPDATE.
Why not just use a stored procedure, then you can embed all the logic there are plus you have a reusable piece of code (e.g. the stored proc) that you can use in other applications. Finally, this only requires one round trip to the server to call the stored proc.