PHP Mysql Insert Batch if not exist - php

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.

Related

UPDATE using JOIN appends only first row value to another table, why?

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.

multiple rows update or insert mysql

I've created a table like this,
id | option_name | value | user_id
----------------------------------------------
1 | name | Joe | 1
----------------------------------------------
2 | age | 30 | 1
----------------------------------------------
3 | sex | male | 1
----------------------------------------------
4 | name | Jane | 2
----------------------------------------------
5 | age | 28 | 2
----------------------------------------------
6 | sex | female | 2
----------------------------------------------
I want to update all rows corresponding of user_id and option_name.
If user_id == 3, when i submit form with option_name (name,sex,age) as fields, if there is no rows with user_id == 3 then insert rows but if rows exist i want to update those row with new values for value field.
Please check my code: http://pastebin.com/THQdYpix
I want to reduce query steps in my code, any idea?
First check if it updates or note if the mysql_query() returns false then you can use insert query and execute the query.
Use INSERT ... ON DUPLICATE KEY UPDATE.If you want to do this in a single statement, I would recommend using the INSERT ... ON DUPLICATE KEY UPDATE syntax, as follows:
INSERT INTO table (id, someothervalue) VALUES (1, 'hi mom') ON DUPLICATE KEY UPDATE someothervalue = 'hi mom';
The initial INSERT statement will execute if there is no existing record with the specified key value (either primary key or unique). If a record already exists, the following UPDATE statement (someothervalue = 3) is executed.
Below query will work.
REPLACE INTO `table1`
( `name`,`sex`,`age` )
VALUES
( 'Mark', '29', 'male' )
ON DUPLICATE KEY UPDATE user_id=3;

Joomla Re-Index mysql table as a function

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."

SQL throws an error when two columns have the same value

I want to insert a record if it does not exist without using unique ID, and I found this answer here: MySQL: Insert record if not exists in table.
In my case I have a table:
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| ID | dRelIns | vRelIns | dRelDel | vRelDel | cRelAktiv | iRelDateiId | iRelKatId |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| 1 | blabla | blabla | NULL | NULL | J | 3 | 5 |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| 2 | blabla | blabla | blabla | blabla | N | 3 | 1 |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
| 3 | blabla | blabla | NULL | NULL | J | 3 | 2 |
+----+---------+---------+---------+---------+-----------+-------------+-----------+
I am getting an array ($_POST) with id iRelKatId and another on id iRelDateiId. I check if the id already exists and cRelAktiv = 'J', if not I want to insert a new one. If some entry exists but it's not in the list, I want to set cRelAktiv to 'N'.
My PHP script with the SQL queries:
$list=implode("','", $_POST["kat"]);
$sql="UPDATE tabRel_UDK SET dRelDel=NOW(),
vRelDel=USER(),
cRelAktiv='N'
WHERE iRelDateiId='$_POST[id]' AND cRelAktiv='J' AND iRelKatId NOT IN('$list')";
$result = mysql_query($sql) or die(Error (" . mysql_error() . ").");
foreach ($_POST["kat"] as $value) {
$sql="INSERT INTO tabRel_UDK (dRelIns, vRelIns, cRelAktiv, iRelDateiId, iRelKatId)
SELECT * FROM (SELECT NOW(), USER(), 'J', '$_POST[id]','$value') AS tmp
WHERE NOT EXISTS (
SELECT iRelDateiId,iRelKatId,cRelAktiv FROM tabRel_UDK
WHERE iRelDateiId = '$_POST[id]' AND iRelKatId='$value' AND cRelAktiv='J') LIMIT 1;";
$result = mysql_query($sql) or die("Error (" . mysql_error() . ").");
}
This script works for me, but when both ids have the same value(for example 5), it throws an error Duplicate column name '5' because of SELECT * FROM (SELECT NOW(), USER(), 'J', '$_POST[id]','$value')
Any ideas how to make it works, or should I make 2-3 SQL queries and check the ids manually in PHP?
I suspect $_POST[id] and $value have the same value, and so you appear to be selecting the same column twice. This should be suppressed in code, so you only select it once - or you should be giving each an alias so this does not happen.
I wouldn't recommend returning a resultset with column names starting with a number anyway - in some database systems that would not be permitted, unless it is quoted. Give them string prefixes as aliases, ending in _<number> if you must.
Thus, your subselect string might look like this:
"SELECT * FROM (
SELECT
NOW(),
USER(),
'J',
'{$_POST['id']}' AS val_1,
'{$value}' AS val_2
) WHERE ..."
More importantly, having $_POST[id] in your code will open you up to SQL injection vulnerabilities - always escape data before using it. Even better, switch to MySQL PDO and use parameterisation.
Lastly, the variable should be $_POST['id'] - PHP assumes that you meant a string index, but it will raise a warning if you skip the quotes. Turn on warnings so you can see mistakes like this.

on duplicate entry add name if empty php mysql

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.

Categories