Ensuring Unique Rows Using PHP/MySQL - php

I have the following code that should, when run, update a table of "victims" of Her Royal Majesty Penelope the Queen of Sheep (it's work for someone, honest), however every time the code is executed it adds all new rows all over again. I was pretty sure I had safeguarded against that, but I guess not. What am I doing wrong here?
require_once 'victims.php';
foreach( $victims as $vic )
{
$vic = mysql_real_escape_string($vic);
if(!(mysql_query("
SELECT * FROM victims
WHERE ".$vic
)))
{
mysql_query("
INSERT INTO victims
(victim, amount)
VALUES( '".$vic."', 0)
");
}
}

You need to change the where clause of your first query to the following:
WHERE victim = $vic
Also, please consider using bind variables as this will protect your code from SQL injection attacks.

You could use an "INSERT ... ON DUPLICATE KEY" query instead, which will guarantee that existing rows won't be duplicated, but only updated. Assuming vic is the table's primary key, you'd do:
INSERT INTO victims (victim, amount)
VALUES ($vic, $amount)
ON DUPLICATE KEY UPDATE amount=VALUES(amount)

Related

How to make my php code faster?

I'am using php on server side to manage data with MySQL.
I have to request a API that gives me an list of users. I need to check for each user if he is in the database.
If yes, I update his information.
If not, I insert him in the data base.
The issue is that there is more than 2000+ users each times and my code in PHP is really slow (sometimes I get 504 Gateway Time-out).
We will have even more users very soon.
How can I make my code faster ? Is Php ok ?
EDIT my codeV3 after improvement:
$userList = getFromAPI();
foreach ($userList as $userId){
$db = dbConnect();
$tagList = implode(",", $user["tagid_list"]);
$query = $db->prepare(
"INSERT INTO USERS(id, name, group) VALUES(:id, :name, :group)
ON DUPLICATE KEY UPDATE name=values(name), group=values(group)"
);
$query->execute([
"id"=>$id,
"name"=>$name,
"group"=>$group
]);
}
Maybe try with putting $db = dbConnect(); outside of your foreach?
I don't know if it is needed to open the connection in each cycle. It may be time consuming aswell.
You can use a single query for that:
INSERT INTO users (id, name)
VALUES (1, 'Alice'), (2, 'Bob'), (3, 'Cecil')
ON DUPLICATE KEY UPDATE name = VALUES(name);
In a nutshell: you insert new rows, but if one already exists (the key is duplicated), it is updated instead. You can build your insert values in a loop so you end up with a single query instead of 4000+.
Read more here.
First of all get fetching all users ids from database out of foreach lopp and buffer it in some variable. Should be better.

ON DUPLICATE KEY UPDATE - Condition WHERE vs CASE WHEN vs IF?

I am refering to this post. I am stuck with a problem I can't resolve. I try to insert multiple rows with a php script into a MySQL database. I don't succeed in updating the whole thing using ON DUPLICATE KEY UPDATE and using a WHERE condition (at the end of the code below) I would like to use to update only an entry has been modified recently:
// for information (used in a foreach loop):
$args[] = '("'.$row['lastname'].'", '.$row['phone'].', "'.$row['lastModification'].'")';
// then:
$stringImplode = implode(',', $args);
// Where I am stuck - WHERE statement:
$sql = $mysqli->query('INSERT INTO table_name '. (lastname, phone, timestamp) .' VALUES '.$stringImplode .'ON DUPLICATE KEY UPDATE lastname=VALUES(lastname), phone=VALUES(phone) WHERE timestamp > VALUES(lastModification);
Everything works fine except I cannot set any WHERE condition at this point that involves multiples entries. Maybe the WHERE statement in this case is not intended to refer to a condition in this statement.
I was told to try with a database procedure using a JOIN statement and a temporary table with first all my entries and then querying some conditions. But I have to admit I don't understand very well how I could leverage such a table to update an other table.
Is there an easy and lovely way to use a "CASE WHEN" or an "IF" statement in this case?
Would something like
INSERT INTO ... ON KEY DUPLICATE UPDATE lastname = VALUES(lastname), phone = VALUES(phone)
CASE WHEN (timestamp > VALUES(lastModification)) THEN do nothing ...
or
...ON KEY DUPLICATE UPDATE... IF (timestamp > VALUES(lastModification)) ...
If anyone could help me, I would be very grateful.
EDIT: Since I will have many variables, could it be used in this way:
INSERT INTO ... ON KEY DUPLICATE UPDATE
IF(timestamp > VALUES(timestamp),
(
name = VALUES(name),
number = VALUES(number),
timestamp = VALUES(timestamp)
....many other variables
),
(
name = name,
number = number,
timestamp = timestamp
....many other variables)
)
You can use simple IF function in value like this:
INSERT INTO ... ON KEY DUPLICATE UPDATE
name = VALUES(name),
number = VALUES(number),
timestamp = IF(timestamp > VALUES(timestamp), VALUES(timestamp), timestamp)
If condition is not met, it will update timestamp with the same timestamp which already exists. It does not matter, because update to same values is optimized before it is even executed, so MySQL will not make real update. You should not afraid of some performance penalty.
EDIT:
IF works likes this:
IF(condition, returned when true, returned when false)
Maybe you need to switch those two arguments to fit your condition like you want.

mysql don't post dupes to table

So I have a database with a table of movies with their respective directors.
I have a form where one can add a director to a movie, but I want to not add duplicates (i.e. someone adds a director to a movie that is already in the movie director table.
I have the following, but for the life of me, I cannot figure out why this still adds the duplicate:
if (isset($_POST["submit"])) {
$movie_id = $_POST[movie];
$director_id = $_POST[director];
echo $movie_id;
echo '<br/>';
echo $director_id;
echo '<br/>';
$add_sql = "INSERT IGNORE INTO MovieDirector (mid, did)
VALUES ($movie_id, $director_id)";
if (mysql_query($add_sql, $db_connection)){
echo "added director to movie ";
}
else {
echo "Failed ";
}
I think you are confused about what the IGNORE modifier keyword does for INSERT statements in MySQL. The role of IGNORE is not to prevent duplicate records from happening, but to make errors silent.
So, there are multiple ways you could go about this:
you could modify your schema to not allow duplicate records and either continue to use the IGNORE keyword, or better yet, handle theerrors
ALTER TABLE MovieDirector ADD UNIQUE INDEX(mid, did);
you could also modify your query to not insert a record if one already exists
IF NOT EXISTS(SELECT * FROM MovieDirector WHERE mid = $movieId AND did = $directorId)
INSERT INTO MovieDirector (mid, did) VALUES ($movieId, $directorId)
You probably want both of the above (probably minus the IGNORE keyword.. that's just going to come and bite you later)
This answer would be incomplete if I did not stress that you should really be using parametrized queries instead of adding the variables directly into the query string!

PHP MYSQL Update query

I currently have the following update statement but is there anyway that I can make it retain the current values but insert and new values that are not in the db?
If not what would be the best way to achieve this?
UPDATE INTO {refocus_candidate_category} SET canid=?, categoryid=? WHERE canid=? AND categoryid=?",array($emailCheck['id'], $id, $emailCheck['id'], $id));
Function:
$catParams = array_merge(array($emailCheck['id']), $fields['Occupation']);
$catPlaceholders = '?'.str_repeat(',?',count($fields['Occupation'])-1);
$catCheck = CMS::selectQuery("SELECT * FROM {table} WHERE canid=? AND categoryid IN (".$catPlaceholders.")", $catParams);
if($catCheck != FALSE)
{
for($i=0; $i<count($fields['Occupation']); $i++) {
$id = $fields['Occupation'][$i];
CMS::updateQuery("UPDATE INTO {table} SET canid=?, categoryid=? WHERE canid=? AND categoryid=?",array($emailCheck['id'], $id, $emailCheck['id'], $id));
}
echo 'found update';
}
ID Print
$fields['Occupation'][$i] = 1678
It's not clear to me from your question precisely what you mean, but there are a number of alternatives for inserts/updates that deal with missing or already present values.
Firstly, if you just want to insert into mysql and have it either create a new row or replace an existing row (where existing is determined by the primary key matching) use REPLACE INTO instead of INSERT INTO. REPLACE INTO tries an insert, but if the primary key already exists, it turns the query into a DELETE and then retries the INSERT.
If you want to insert a new row but leave an existing row alone if you've already got one, you can either use INSERT IGNORE INTO (which may also fail to insert if you've got your data types or column info wrong...) or INSERT INTO ... ON DUPLICATE KEY UPDATE which allows you to do much finer grained control of how you handle inserts of items that already exist.
There's other options as well, but those are probably the most relevant.

Check for duplication before insertion

Problem
I have a table tbl_student_courses which join 2 tables student and courses now when data is inserted it is the combination of 2 ids course_id and student_id. I just want there would be no duplication of this combination in tbl_student_courses.
Code
foreach($_POST['sel_course'] as $val) {
$query_std_course = "
INSERT INTO
`tbl_student_courses`
SET
`course_id` = '".$val."',
`std_id` = '".$_POST['std']."',
WHERE NOT EXISTS (
SELECT * FROM `tbl_student_courses` WHERE course_id=$val AND std_id=$std
)";
}
Help
This query giving SQL syntax error.
Can any body help me?
Thanks in advance.
Probably you are missing quotes one inner query values.
You SQL query should look like this
$sql = "
INSERT INTO
`tbl_student_courses`
SET
`course_id` = '".$val."',
`std_id` = '".$_POST['std']."',
WHERE NOT EXISTS (
SELECT * FROM `tbl_student_courses` WHERE course_id='".$val."' AND std_id='".$std."'
)";
NOTE: Inserting in database not prepared statements like std_id = '".$_POST['std']."' is not of a good manner. Consider using PDO or filter data yourself, bec. this can be easily used for SQL Iinjection therefore it is potential security breach.
UPDATE: Try to use ON DUPLICATE KEY UPDATE or INSERT IGNORE INTO table.
You can find more information regarding your implementation - http://bogdan.org.ua/2007/10/18/mysql-insert-if-not-exists-syntax.html
And read about proposed implementation - http://dev.mysql.com/doc/refman/5.1/en/insert-on-duplicate.html
The SQL syntax you seek is the MERGE statement, or its equivalent on your platform
http://en.wikipedia.org/wiki/Merge_(SQL)

Categories