8

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.

tony9099
  • 4,567
  • 9
  • 44
  • 73
  • You can make your `email` column `UNIQUE`, use `ALTER TABLE ADD UNIQUE (email)`, then you could use `ON DUPLICATE KEY UPDATE`.
    – Tobias F. Mar 10 '17 at 07:30
  • Possible duplicate of [MySQL insert on duplicate update for non-PRIMARY key](http://stackoverflow.com/questions/33495194/mysql-insert-on-duplicate-update-for-non-primary-key) – Aziz Shaikh Mar 10 '17 at 07:31

5 Answers5

14

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.

Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
5

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')
Diru
  • 51
  • 4
  • this solution will work well if the selection critiria is based on multiple fields. – Bryan Jyh Herng Chong Sep 30 '19 at 05:45
  • 3
    This doesn't work if the update statement doesn't change the record's values. That is, if the record with `email`='value3' already has `country`='value1' and `lastlogin`='value1', then the ROW_COUNT() function returns zero. The record already exists but the insert happens anyways. – Dan Apr 28 '20 at 20:12
  • Thanks for the correction Dan. I mistakenly assumed ROW_COUNT() to be the functional equivalent of @@ROWCOUNT in MSSQL. – Diru Jun 05 '20 at 07:55
  • Can someone help me with how to set the FOUND_ROWS option in the pydobc connection? I can see the option that you mention in Table 5.3 here - https://dev.mysql.com/doc/connector-odbc/en/connector-odbc-configuration-connection-parameters.html but I can't find an example of how to set it anywhere. Here's my connection string: ` mysql_conn = pyodbc.connect("Driver={ODBC Driver 17 for SQL Server};" "Server=111.11.11.111,42300;" "Database=MyDatabase;" "UID=my-user;" "PWD=MyPassword;")` – MikeA Aug 30 '23 at 17:35
0

you can use

$query=mysql_query("select * from table where email = 'your email'");
if(mysql_num_rows($query) > 0){
//update
}else{
//insert
}
0

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.

mm759
  • 1,404
  • 1
  • 9
  • 7
0

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
  }
Dani
  • 905
  • 7
  • 14