Clarification of what I'm trying to accomplish:
Update "user name", if there is a record with the same e-mail but no name. if user already has a name, then don't make any changes
I have a website where all users can be "subscribers, entrepreneurs or investors". If a subscriber (of whom I have previously only asked for email) chooses to upload a business idea then that person will probably use the same e-mail address as before only this time adding a name. So I'd like to INSERT INTO, and if e-mail already exists - add the name, but only if there is not a name there already (so that a person cannot simply over write somebody else's details).
I've gotten this far:
mysql_query("
INSERT INTO users
(email, name)
VALUES
('" .$epost. "', '" .$namn. "')
ON DUPLICATE KEY UPDATE
name=VALUES(name) -->[if name == '', else do nothing...]
");
Now it replaces the current name with a new one if different.
I searched "on duplicate update if field empty"
and found:
http://forums.aspfree.com/sql-development-6/on-duplicate-key-update-but-only-if-value-isn-t-482012.html (merging?)
conditional on duplicate key update (closer, but I don't want to update it if it differs, only if the field is empty.)
http://bytes.com/topic/php/answers/914328-duplicate-key-update-only-null-values (if the input is blank.. well it's not)
http://boardreader.com/thread/Insert_on_duplicate_key_update_only_if_c_can8Xachr.html (the layout of this page got me lost)
http://www.digimantra.com/tutorials/insert-update-single-mysql-query-duplicate-key/ (it simply updates)
I believe this might be kind of what I'm after (?) http://thewebfellas.com/blog/2010/1/18/conditional-duplicate-key-updates-with-mysql but I haven't managed to make it work
This code:
mysql_query("UPDATE users SET name='".$namn."'
WHERE email='".$epost."' AND name =''");
updates the name, only if it's previously null, and that's what I'm after however it does not insert a new record if email doesn't already exist.
My table
So I tried this:
mysql_query("
INSERT INTO users
SELECT email, 'victoria' FROM users
WHERE email='victoria#hejsan.se' ON DUPLICATE KEY UPDATE name = 'victoria'
");
and I tried this:
mysql_query("
INSERT INTO users
SELECT email, 'yay' from users
WHERE email='victoria#hejsan.se'
ON DUPLICATE KEY
UPDATE name = values(name)
");
from #Fluffeh 's answer
but nothing happens. Did i misinterpret the answer?
It just hit me that if someone already has an account then they should also have a password already, and so I'll just ask them to verify their password, and make sure I do an AJAX call while they insert their e-mail to see if the e-mail is already registered :) And so then this is no longer an issue, and I think that is the solution I'll go with. !)
The only way that you could use the insert .... on duplicate key... syntax to solve your issue would be if name and email made a composite key - and I think you would be better off using an auto_increment as a primary key.
You might have to put a little logic into the PHP to do a check first, then insert or update - or write a function to do that same test for you - but neither will be a simply query that you can just fire off.
Edit: Not sure if this is what you want to do, but I think that the best solution for your requirements is to actually use two tables in a one to many relationship.
Table-Users
id | email | name
create table users(
id int(10) not null auto_increment,
email varchar(100),
name varchar(100),
primary key(email, name)
);
Table-Ideas
id | userID | idea
create table users(
id int(10) not null auto_increment primary key,
userID int(10) not null,
idea text
);
With the primary key on the table, you can safetly do an insert... duplicate... without worrying about over-writing folks. The second table will however allow you to have the ideas stored safetly locked to the user, and let you have a number of ideas per user. As the relationship is the users.id to ideas.userID you won't lose who owns it even if their details are updated.
Edit: (aka, ZOMG facepalm)
$query="
update users
set name='".$userName."'
where
email='".$userEmail."'
and name is null";
Edit 2: (aka, wipes brow)
insert into users
select email, '".$namn."' from users where email='".$epost."'
on duplicate key
update name = values (name);
and here it is working:
mysql> create table test1 (myName varchar(10) unique, myEmail varchar(10));
Query OK, 0 rows affected (0.02 sec)
mysql> insert into test1 values ('Tom','something');
Query OK, 1 row affected (0.01 sec)
mysql> insert into test1 values('Nick',null);
Query OK, 1 row affected (0.00 sec)
mysql> select * from test1;
+--------+-----------+
| myName | myEmail |
+--------+-----------+
| Tom | something |
| Nick | NULL |
+--------+-----------+
2 rows in set (0.00 sec)
mysql> insert into test1 select myName, myEmail from test1
where myName='Tom' on duplicate key update myEmail = values (myEmail);
Query OK, 0 rows affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test1;
+--------+-----------+
| myName | myEmail |
+--------+-----------+
| Tom | something |
| Nick | NULL |
+--------+-----------+
2 rows in set (0.00 sec)
mysql> insert into test1 select 'Tom', myEmail from test1
where myName='Tom' on duplicate key update myEmail = values (myEmail);
Query OK, 0 rows affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test1;
+--------+-----------+
| myName | myEmail |
+--------+-----------+
| Tom | something |
| Nick | NULL |
+--------+-----------+
2 rows in set (0.00 sec)
mysql> insert into test1 select myName, 'Something Else' from test1
where myName='Tom' on duplicate key update myEmail = values (myEmail);
Query OK, 2 rows affected, 1 warning (0.01 sec)
Records: 1 Duplicates: 1 Warnings: 1
mysql> select * from test1;
+--------+------------+
| myName | myEmail |
+--------+------------+
| Tom | Something |
| Nick | NULL |
+--------+------------+
2 rows in set (0.00 sec)
mysql> insert into test1 select myName, null from test1
where myName='Nick' on duplicate key update myEmail = values (myEmail);
Query OK, 0 rows affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
mysql> select * from test1;
+--------+------------+
| myName | myEmail |
+--------+------------+
| Tom | Something |
| Nick | NULL |
+--------+------------+
2 rows in set (0.00 sec)
mysql> insert into test1 select myName, 'yay' from test1
where myName='Nick' on duplicate key update myEmail = values (myEmail);
Query OK, 2 rows affected (0.01 sec)
Records: 1 Duplicates: 1 Warnings: 0
mysql> select * from test1;
+--------+------------+
| myName | myEmail |
+--------+------------+
| Tom | Something |
| Nick | yay |
+--------+------------+
2 rows in set (0.00 sec)
Edit 3: Try this for your $query
insert into table1 select coalesce(email,'".$epost."') as email, coalesce(name,'".$namn."') as name from table1
where email='".$epost."' on duplicate key update name = values (name);
If you want to update a field that is already exist, you can do this as;
-- MySQL Reference
INSERT INTO table (a,b,c) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE c=VALUES(a)+VALUES(b);
-- so your code
INSERT INTO users
(email, name)
VALUES
('" .$epost. "', '" .$namn. "')
ON DUPLICATE KEY UPDATE email=VALUES(email), name=VALUES(name)
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
UPDATE
At this point, you need "MySQL conditional insert". Let's try it;
CREATE TABLE IF NOT EXISTS `users` (
`name` varchar(50) NOT NULL,
`email` varchar(255) NOT NULL,
UNIQUE KEY `email` (`email`)
)
INSERT INTO users (name, email) VALUES('kerem', 'qeremy[atta]gmail[dotta]com');
INSERT INTO users (name, email) VALUES('test', 'test#example.com');
>> 2 rows inserted. ( Query took 0.0005 sec )
-- this is your part (regarding email field is UNIQUE, so WHERE email='search email')
INSERT INTO users (name, email)
SELECT 'test', 'test#example.com' FROM DUAL WHERE NOT EXISTS (
SELECT * FROM users WHERE email = 'test#example.com' LIMIT 1
);
>> 0 rows inserted. ( Query took 0.0003 sec )
https://www.google.com/search?q=conditional+insert+mysql
http://allurcode.com/2011/04/15/mysql-conditional-insert/ (which is useful search result)
UPDATE 2
If this does not work for you, then you can do your work like (just an input);
mysql_query("INSERT IGNORE INTO users (name, email) VALUES('$name', '$email')");
if (!mysql_insert_id()) {
mysql_query("UPDATE users SET name='$name' WHERE name='' AND email='$email'");
}
Or;
mysql_query("UPDATE users SET name='$name' WHERE name='' AND email='$email'");
if (mysql_affected_rows() < 1) {
mysql_query("INSERT INTO users (name, email) VALUES('$name', '$email')");
}
I'd like to suggest this solution using the control function IFNULL(exp1,exp2), defined as "if exp1 is not null, returns exp1; if exp1 is null, returns exp2".
http://dev.mysql.com/doc/refman/5.7/en/control-flow-functions.html
INSERT INTO users (name, email) VALUES ('$name','$email')
ON DUPLICATE KEY UPDATE name = IFNULL(name, VALUES(name))
Of course you must be beyond this somehow, but it helped me.
Related
I have searched that there is already a way in inserting avoiding the duplicate error
ref: MySQL: Insert record if not exists in table
INSERT INTO table_listnames (name, address, tele)
SELECT * FROM (SELECT 'Unknown' AS name, 'Unknown' AS address, '022' AS tele) AS tmp
WHERE NOT EXISTS (
SELECT name FROM table_listnames WHERE name = 'Unknown'
) LIMIT 1;
Query OK, 1 row affected (0.00 sec)
Records: 1 Duplicates: 0 Warnings: 0
SELECT * FROM `table_listnames`;
+----+---------+-----------+------+
| id | name | address | tele |
+----+---------+-----------+------+
| 1 | Rupert | Somewhere | 022 |
| 2 | John | Doe | 022 |
| 3 | Unknown | Unknown | 022 |
+----+---------+-----------+------+
is there a way for this to do in batch?
or how is the format in adding data as a batch
ref: insert multiple rows via a php array into mysql
Planning to integrate this one
$sql = array();
foreach( $data as $row ) {
$sql[] = '("'.mysql_real_escape_string($row['text']).'", '.$row['category_id'].')';
}
mysql_query('INSERT INTO table (text, category) VALUES '.implode(',', $sql));
is there a way?
I would suggest using the ON DUPLICATE KEY syntax for this. This will simplify the query, and allow the use of the VALUES() statement, which is handy to pass parameters from your application.
For this to work, you need a unique (or primary key) constraint on colum name. Create it if it does not exist:
create unique index idx_table_listnames on table_listnames(name);
Then, you can do:
insert into table_listnames(name, address, tele)
values('Unknown', 'Unknown', '022')
on duplicate key update name = values(name)
The conflict clause traps violations on the unique index, and performs a no-op update.
Side note: use parameterized queries to pass data from your application to the query; escaping input is not enough to make your query safe.
I have a target table which crossed over 1M rows. Each time I will be getting 50K rows which may contain multiple duplicated entries. Hence I have decided to store CSV data into a temp table, then from temp_table to target_table by comparing rows between two tables...
If duplicated entries found append data from temp_table to target_table else Insert into the table... I am using partition here, so ON DUPLICATE key update is not working here.. in temp_table I am not using any KEYS
I have two tables which look like below
temp_table
Name | Type
John | Civil
John | Mech
target_table
Name | Type
John | Civil
When I run below query, I am getting an output of single row
UPDATE target_table JOIN temp_table
ON temp_table.Name = target_table.Name
SET target_table.Type = IF((LOCATE(temp_table.Type, target_table.Type) > 0)
target_table.Type,CONCAT(target_table.Type,',',temp_table.Type))
target_table
Name | Type
John | Civil
I am expecting output to be like below
target_table
Name | Type
John | Civil, Mech
May I know where it went wrong?
you should use a group_concat and use a subquery in join
UPDATE target_table
JOIN (
select name, group_concat(Type) grouped
from temp_table
group by name
) t ON t.Name = target_table.Name
SET target_table.Type = t.grouped
I suspect (but don't know for sure) and hopefully someone who does know will jump in and correct me, that an update join does not create a cartesian product in the way that a select would. As an attempted proof
truncate table temp_table;
insert into temp_table values
( 'John' , 'mech' ),
( 'John' , 'abc' );
truncate table target_table;
insert into target_table values
('john', 'civil', 9 );
UPDATE target_table JOIN temp_table
ON temp_table.Name = target_table.Name
set target_table.type = (concat(target_table.Type,',',temp_table.Type));
select * from target_table;
+------+------------+------+
| Name | Type | LOC |
+------+------------+------+
| john | civil,mech | 9 |
+------+------------+------+
1 row in set (0.00 sec)
note that abc from temp_table is ignored and mech is selected purely by chance.
if we change the order in temp_table
truncate table temp_table;
insert into temp_table values
( 'John' , 'abc' ),
( 'John' , 'mech' );
truncate table target_table;
insert into target_table values
('john', 'civil', 9 );
UPDATE target_table JOIN temp_table
ON temp_table.Name = target_table.Name
set target_table.type = (concat(target_table.Type,',',temp_table.Type));
select * from target_table;
we get
+------+-----------+------+
| Name | Type | LOC |
+------+-----------+------+
| john | civil,abc | 9 |
+------+-----------+------+
1 row in set (0.02 sec)
where abc is picked purely by chance.
In my view the safest way to do this is on a row by row basis ie a cursor.
I have three fields in my database: first name, lastname and email. Email is my primary key. I don't have any other fields in my database.
I need to find a mysql query which can delete duplicated primary keys and their values from the database leaving only one unique email in the database.
I use the following command to display all duplicated primary keys. It worked, but I need to delete all other duplicate entries and keep only one. I am using php programming.
SELECT *
FROM table_name
WHERE primarykey IN (
SELECT primarykey
FROM table_name
GROUP BY primarykey
HAVING count(primarykey) > 1
)
ORDER BY primarykey
Populate a temp table with the ones you want to keep, using GROUP BY, HAVING and MAX on the other columns. Then run your query which deletes too much, then put your copied ones back in. And then make it the actual PK so it doesn't happen again.
You cannot do this with just 1 query, as you will need to use limit and that one needs to be set hard. (You cannot say limit someColumn for example.)
$query = "select primarykey, count(primarykey) as count from table_name group by primarykey having count(primarykey) > 1"
$result = $mysqli->query($query);
while ($row = $result->fetch_assoc()) {
$query = "delete from table_name where primarykey = ? limit " . $row['count'];
$stmt = $mysqli->prepare($query);
$stmt->bind_param('s', $row['primarykey']);
$stmt->execute();
}
Email is not your primary key. Primary keys have a constraint on them where duplicates are not allowed. Your problem, by the way, is just an example of why you want to have an auto-incrementing numeric primary key on all tables. It seems too late for that.
One way to solve your problem is using temporary tables. The idea is to copy the data over, and tehn re-insert it:
create temporary table tmp_emails as
select email, firstname, lastname
from emails
group by email;
truncate table emails;
insert into emails(email, firstname, lastname)
select email, firstname, lastname
from tmp_emails;
Could you try this?
DELETE t1 FROM test t1, test t2
WHERE t1.email = t2.email
AND t1.fn > t2.fn
AND t1.ln > t2.ln;
Here are tests:
CREATE TABLE test
(
email varchar(100),
fn varchar(100),
ln varchar(100)
);
INSERT INTO test VALUES('a#b', 'f1', 'l1');
INSERT INTO test VALUES('a#b', 'f2', 'l2');
INSERT INTO test VALUES('c#d', 'f2', 'l2');
mysql> SELECT * FROM test;
+-------+------+------+
| email | fn | ln |
+-------+------+------+
| a#b | f1 | l1 |
| a#b | f2 | l2 |
| c#d | f2 | l2 |
+-------+------+------+
3 rows in set (0.00 sec)
mysql> DELETE t1 FROM test t1, test t2
-> WHERE t1.email = t2.email
-> AND t1.fn > t2.fn
-> AND t1.ln > t2.ln;
Query OK, 1 row affected (0.00 sec)
mysql> SELECT * FROM test;
+-------+------+------+
| email | fn | ln |
+-------+------+------+
| a#b | f1 | l1 |
| c#d | f2 | l2 |
+-------+------+------+
2 rows in set (0.00 sec)
ALTER TABLE table_name RENAME TO table_name_bak;
CREATE TABLE table_name AS SELECT * FROM table_name_bak LIMIT 0;
ALTER TABLE table_name ADD PRIMARY KEY (email);
INSERT IGNORE INTO table_name SELECT * FROM table_name_bak;
I am tring to re-index a table with a function inside php/joomla ...
it does nothing. I can not make the entire set of slq commands wihtin one string either.
function ReNumberID($TABLENAME ,$COLUMNNAME) {
$sql = "set #a=0; " ;
$db = JFactory::getDbo();
$query = $db->getQuery(true);
$db->setQuery($sql);
$db->execute();
$sql2 = "UPDATE `".$TABLENAME."` SET `".$COLUMNNAME."`=(#a:=#a+1); " ;
$db->setQuery($sql2);
$db->execute();
$sql3 = "SELECT * FROM `".$TABLENAME."` WHERE 1" ;
$db->setQuery($sql3);
$db->execute();
$newindexnumber = $db->getNumRows();
$newindexnumber++ ;
$sql4 = "ALTER TABLE `".$TABLENAME."` auto_increment = ".$newindexnumber." ;";
$db->setQuery($sql4);
$db->execute();
}
First of all, I'd recommend that you check each of your queries to see whether they succeed, and how many rows are affected. You are currently calling execute() and trusting that something actually happened. Who knows if you spelled a column name wrong or got a privilege error or something.
Second, you should make sure you are applying the update in order from the current low id number ascending. Because you could easily cause an error. Here's an example:
mysql> create table bar (id int primary key, x int) engine=myisam;
mysql> insert into bar (id) values (1), (5), (7), (2);
mysql> select * from bar;
+----+------+
| id | x |
+----+------+
| 1 | NULL |
| 5 | NULL |
| 7 | NULL |
| 2 | NULL |
+----+------+
mysql> set #a := 0;
mysql> update bar set id = (#a:=#a+1);
ERROR 1062 (23000): Duplicate entry '2' for key 'PRIMARY'
The reason is that id 1 is set to 1, then id 5 is set to 2, which conflicts with the fourth row.
mysql> update bar set id = (#a:=#a+1) order by id;
Query OK, 3 rows affected (0.00 sec)
mysql> select * from bar;
+----+------+
| id | x |
+----+------+
| 1 | NULL |
| 3 | NULL |
| 4 | NULL |
| 2 | NULL |
+----+------+
That at least worked. I never would have known about the duplicate key error if I hadn't checked for errors.
By the way, you can just set ALTER TABLE ... AUTO_INCREMENT=0 and the table will automatically adjust it to the max(id)+1.
But here's my stronger recommendation:
You don't need to renumber the auto-increment key. The primary key must be unique, but it's not required to be consecutive.
It's normal to have gaps. This happens when an INSERT fails, or you DELETE a row, or if you INSERT but then roll back.
You can get problems if you renumber the primary key of rows throughout your table. For instance, if your application communicated outside the database, external systems may have a record of an entity by the old id.
Example: abusive user 1234 harasses other users and gets himself banned and his account shut down and deleted. Then you renumber all the id's and allocate 1234 to another new user. The next day, a lawyers shows up and serves you with a civil complaint against user 1234. The poor new user is blamed for something someone else did.
I wrote about this in my book, SQL Antipatterns Volume 1: Avoiding the Pitfalls of Database Programming. The chapter about this mistake is called "Pseudokey Neat-Freak."
When i use this SQL command, duplicate rows will insert.
SQL command is:
$dbh = mysql_connect(db_host, db_user, db_pass);
mysql_select_db(db_name, $dbh);
mysql_query("INSERT INTO test VALUES(0, '1')");
this happened just when i use 0 for first field that is primary and auto_increment
I fail to see the problem:
mysql> use test;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A
Database changed
mysql> create table test (x int primary key auto_increment, y varchar(1));
Query OK, 0 rows affected (0.00 sec)
mysql> insert into test values (0, '1');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values (0, '1');
Query OK, 1 row affected (0.00 sec)
mysql> insert into test values (0, '1');
Query OK, 1 row affected (0.00 sec)
mysql> select * from test;
+---+------+
| x | y |
+---+------+
| 1 | 1 |
| 2 | 1 |
| 3 | 1 |
+---+------+
3 rows in set (0.00 sec)
mysql> insert into test values (3,'1');
ERROR 1062 (23000): Duplicate entry '3' for key 'PRIMARY'
This is standard MySQL behavior. Inserting a 0 into a primary key/auto_increment column is the same as inserting a null - MySQL will re-write the value into the auto_increment value.
you need to declare your insert columns. instead of a blind insert you would want it to go something like this:
column names in table A (id, name, address, phone)
id is set to auto increment
INSERT INTO table A (name, address, phone) values ('John Doe', '123 Street', '1231231234')
doing it this way will allow the auto increment to work in the id column. if you need to insert multiple rows at the same time you can do it like this:
INSERT INTO table A
(name, address, phone) values
('John Doe', '123 Street', '1231231234')
,('Jane Doe', '124 Street', '1231231235')
,('Joe Doe', '126 Street', '1231231236')
Each row will be given a unique id. If you then did
SELECT * from table A you would get this as a result:
1, John Doe, 123 Street, 1231231234
2, Jane Doe, 124 Street, 1231231235
3, Jake Doe, 126 Street, 1231231236
Strangely the problem was firefox browser cache!
I just tried to reset firefox in safe mode and the problem is solved now.