Can While Loop be used for Error Catching? - php

I am using try catch algorithm when inserting a record to a MySQL table. My scripting language is PHP.
try {
/*
UDID generation algo goes here.
*/
$sql = "INSERT INTO tablex (udid, name)
VALUES ('$udid', 'Doe')";
$conn->exec($sql);
echo "New record created";
}
catch(PDOException $e)
{
echo "Error"
}
$conn = null;
How do I re-write the above so that instead of try catch, I use a loop. If there is an error, try again. Break out of the loop if there is no error.
There is "While True" but I don't know if the "Try Catch" should be part of the While True loop..
The purpose of this is to save a UDID - the unique value is set in MYSQL. If I generate the same value, I may get the error. Hence, why the loop.

I feel like you're going about this the wrong way. Instead of trying to insert a value that might not be unique, I would try to see if that value exists first. You could perform a query such as
do {
//$udid = create uuid
$query = "SELECT COUNT(*) FROM tablex WHERE udid = :udid";
$statement = $pdo->prepare($query);
$statement->bindValue("udid", $udid);
$result = $statement->fetchAll();
} while ($result["count"] === 1);
//insert row into table
This is just off the top of my head and it can be refactored even better. You could also leverage your database to generate the UDID for you if you prefer. You could run a query to get all of the udid's from your table and just run in_array to check to see if the value is there, then you're only hitting your database twice. Anyway, you really don't want to try to abuse a try catch like that.

mysql has a function for something like this you would add an "ON DUPLICATE KEY UPDATE" to your insert statement
Example:
INSERT INTO table(x, y, z) values (?, ?, ?) ON DUPLICATE KEY UPDATE x=?;
Also see this link for more info:
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html

Related

SQL INSERT INTO table results in duplicates

I have a script that I have setup a CRON for that is getting values from a 3rd party server via JSON (cURL)
Right now every time the cron runs it will INSERT a completely new record. Causing duplicates, and resulting me in manually removing the dups.
How would I go about preventing duplicates, and only update the information that is either missing, or different from the NEW $VAR values?
What I want to do can be expressed like this: IF old value is NOT new value use new value else use old value;
if ($stmt->num_rows !== 1) {
if ($insert_stmt = $mysqli->prepare("
INSERT INTO members (
start_date
)
VALUES (?)"))
{
$insert_stmt->bind_param('s',
$StartDate,
);
if (! $insert_stmt->execute()) { echo ''; }
}
}
}
You should try using INSERT ... ON DUPLICATE KEY UPDATE. Documentation
This does mean that you will have to define some unique (could be primary) key to the table that is always constant so MySQL knows what to update.
A quick example of how you would do it:
INSERT INTO table (f1,f2,f3) VALUES ('something_unique',2,5)
ON DUPLICATE KEY UPDATE f2=2,f3=5
The following statement will be silently ignored if one of the fields with the flags UNIQUE or PRIMARY KEY already exist in the database. If you're searching for INSERT IF NOT EXISTS this is probably what you're looking for:
INSERT IGNORE INTO `members` SET name='Steve',start_date='2015-11-20';
You can also overwrite a record that already exists using REPLACE. If it doesn't yet exist, it will be created:
REPLACE INTO `members` SET name='Steve',start_date='2015-11-20';
Another thing to consider would be INSERT ... ON DUPLICATE KEY UPDATE syntax:
INSERT INTO table (a,b,c) VALUES (1,2,3)
ON DUPLICATE KEY UPDATE c=c+1;
UPDATE table SET c=c+1 WHERE a=1;
I ended up writing another if statement to check if a unique value existed from incoming and the existing db value existed and leaving it blank to prevent it from importing duplicates. I also wrote a separate file to update where values differentiate between what I am receiving as (new) and what is in the database (old) which actually worked out great for my application.
Here is my answer for anyone else that runs into this issue :)
$prep_stmt = "SELECT * FROM table WHERE column_keys=?";
$stmt = $mysqli->prepare($prep_stmt);
if ($stmt) {
$stmt->bind_param('s',$varvalues);
$stmt->execute();
$stmt->store_result();
if ($stmt->num_rows == 1) {
if ($insert_stmt = $mysqli->prepare("")) {
$insert_stmt->bind_param('');
if (! $insert_stmt->execute()) {
echo 'shits broke'; }
}
}
else { if ($insert_stmt = $mysqli->prepare("
INSERT INTO table (column_keys)
VALUES (?)")) // you will need a ? per column seperate by a , (?,?,?...?)
{ $insert_stmt->bind_param('s',
$varvalues
); // you will also need to bind a 's' (string) 'i' for num, etc per $var value.
if (! $insert_stmt->execute()) { echo 'shits broke';} //lol
}
}
}
Also a simple error reporting trick I stumbled upon that helped me clean up a few things I overlooked. Just place it at the top of the file, or above you want to debug ;)
error_reporting(E_ALL);

PHP MySQL PDO duplicates

I have the below code, which works perfect. What i want to do is to check the refNo first to see if there are duplicates entries in MySQL. If there is then appear a warning message, otherwise appear a "ok" message. How can i do that with PDO? Any help?
(include("db.php"));
$SQLquery = "INSERT INTO mydatabase (refNo, name)
VALUES ('".$_POST["refNo"]."', '".$_POST["name"]."');";
$STH = $dbc->query($SQLquery);
?>
edit: Hello guys,
i prefer not to add primary keys. Is there any other way?
Set up refNo as a primary key. You could also create it as unique but that defeats the purpose - your reference number appears to be a unique primary identifier. Perfect choice for a primary key.
Further, change your query
try {
$SQLquery = "INSERT INTO mydatabase (refNo, name) VALUES (:refNo, :name)";
$SQLquery = $dbc->prepare($SQLquery);
$SQLquery->bindValue(':refNo', $_POST['refNo']);
$SQLquery->bindValue(':name', $_POST['name']);
$SQLquery->execute();
} catch (Exception $e) {
die("Insert error");
}
$count = $SQLquery->rowCount();
if ($count == 1) {
echo "Record added!";
}
This binds the post value to prevent SQL injection too.
Edit: You could follow this up with $count = $SQLquery->rowCount(); which will be 1 if the insert was successful, as it appears you've edited your question since you posted it for more info.
If you want to do this without using a database level constraint, you'll need to do an extra SELECT statement before inserting into the table. But that gives you no absolute guarantees, as it might be two processes want to insert the same row at the same time and they will still succeed.
-- it'll look a little something like this; I'm not familiar with PDO but the structure should be the same
$selectQuery = "SELECT * FROM mydatabase
WHERE refno = '".$_POST["refNo"]."'";
$res = $dbc->query( $selectQuery );
if( $res->count() > 0 ) {
// this result already exists; show error
}
else {
// this result is new; put the insert query here
}

How to prevent duplication of values for a columns pair when doing a MySQL INSERT?

A table in my DB has the following columns: ID, campaign_id, opt_out_day
The method that inserts a set of "opt-out-days" - an array of DATETIME values - is as follows:
/**
* #param Integer $campaignId
* #param Array $optOutDays Array of DATETIME values
*/
public function addCampaignOptOutDays($campaignId, $optOutDays) {
$query = "INSERT INTO `".self::$tblOptOutDays."`
(campaign_id, opt_out_day)
VALUES
(:campaign_id, :opt_out_day)";
try {
$this->connection->beginTransaction();
$query = $this->connection->prepare($query);
$query->bindParam(':campaign_id', $campaignId, \PDO::PARAM_INT);
foreach ($optOutDays as $day) {
$query->bindParam(':opt_out_day', $day, \PDO::PARAM_STR);
$query->execute();
}
$this->connection->commit();
} catch (\PDOException $e) {
$this->connection->rollback();
throw new \Models\Database\DatabaseException($e->getMessage());
}
}
How can I modify the query in order to prevent duplicating the same opt-out-day for a campaign? In other words, multiple rows with the same opt-out-day can exist in this table, as long as they have different a 'campaign-id'.
Adding a unique key for the (campaign_id, opt_out_day) is not an option though, as I don't want to throw exceptions when such situations occur, I just want to not add the pair again.
Try using the INSERT ... ON DUPLICATE KEY UPDATE id=id
http://dev.mysql.com/doc/refman/5.0/en/insert-on-duplicate.html
This will avoid an extra SELECT query but will also avoid an error if you have duplicate keys.
There's also INSERT IGNORE ... but that might ignore other errors as well
As Jakub Kania commented, you could use a unique index and use INSERT IGNORE:
With IGNORE, the row still is not inserted, but no error occurs.
Ignored errors may generate warnings instead, although duplicate-key
errors do not.
Then, simply check the affected rows value to see if the insert was successful.
So, other errors can still be detected, as warnings. I think INSERT ... ON DUPLICATE KEY UPDATE is a better solution, given you add the unique index because checking warnings can be a pain.
Im not familiair with php, but what if you select from the table and check if that returns a value, if not then insert?
Try
$checkquery = "SELECT 1 FROM `".self::$tblOptOutDays."`
WHERE campaign_id=:campaign_id AND opt_out_day=:opt_out_day)";
Then
IF $checkquery <> 1 THEN
// run insert

Select and update not working

I have a table viewer with id, ip, date_last_viewed & blog_id as the columns. I'm first checking whether a particular entry having the same IP and blog_id is present or not. If yes, it updates the date. Else, it inserts a new entry.
My code is below:
$search_ip = mysql_query("SELECT ip FROM viewer WHERE ip = '".$_SERVER['REMOTE_ADDR']."' AND blog_id= '".$b_id."' ");
if ($search_ip == false){
$insert_ip = mysql_query("INSERT INTO viewer (ip, blog_id, date_last_viewed) VALUES ('".$_SERVER['REMOTE_ADDR']."', '".$b_id."', NOW())");
}
else {
$update_ip = mysql_query("UPDATE viewer SET date_last_viewed = NOW() WHERE ip = '".$_SERVER['REMOTE_ADDR']."' AND blog_id='".$b_id."' ");
}
The table is not inserting anything. What am I doing wrong here? Also, as I'm new to PHP programming, could someone tell me how to modify the above code to PDO?
You can actually do it in just one query.
MySQL has a special feature called INSERT ... ON DUPLICATE KEY UPDATE which basically insert if the record does not exist or update if it already exists. One thing you need to do is to define a unique column(/s)
INSERT ... ON DUPLICATE KEY UPDATE Syntax
Based on your statement, you need to define a unique constraint on both column,
ALTER TABLE viewer ADD CONSTRAINT vw_uq UNIQUE (ip, blog_id)
and execute this statement,
INSERT INTO viewer (ip, blog_id, date_last_viewed)
VALUES ($_SERVER['REMOTE_ADDR'], b_id, NOW())
ON DUPLICATE KEY UPDATE date_last_viewed = NOW()
As a sidenote, the query is vulnerable with SQL Injection if the value(s) of the variables came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?
Assuming your mysql_query executes correctly, it wont return false. What you should do is check the number of rows it returns. You can do this using mysql_num_rows.
Also, take note of the big red warning box at the top of the mysql_* man pages.
You should first add error handlers. Then move to mysqli_ and use prepared statements.
$search_ip = mysql_query( "SELECT ... " ) or die( mysql_error() );
if( mysql_num_rows($search_ip) == 0 ) {
$insert_ip = mysql_query( "INSERT ... " ) or die( mysql_error() );
}
else {
$update_ip = mysql_query( "UPDATE ... " ) or die( mysql_error() );
}
$search_ip will never == false, because it is a reference to the result. Use mysql_num_rows($earch_ip) instead. Also note that mysqli replaces this and your code is actually deprecated
That's not the right way to check if a query returned a value:
$search_ip = mysql_query("SELECT ip FROM viewer WHERE ip = '".$_SERVER['REMOTE_ADDR']."' AND blog_id= '".$b_id."' ");
if (mysql_num_rows($search_ip)==0) {
....
}

insert a record or if exist then update in mysql doesnt work

i want that if a record doesnt exist i add it otherwise update it... but it doesnt work, whats the wrong with this code:
<?php
$user_id=$_POST['user_id'];
$user_email="user_email";
$last_stage=$_POST['last_stage'];
$score=$_POST['score'];
$note=$_POST['note'];
$con=mysqli_connect("localhost","ferfer","Drfrj","ferfw");
$result = mysqli_query($con,"SELECT user_email FROM rating WHERE user_email='".$user_email."'");
$num_rows = mysqli_num_rows($result);
if ($num_rows > 0) {
//echo "exist";
mysqli_query($con,"UPDATE rating SET user_id=".$user_id.", user_email='".$user_email."', last_stage=".$last_stage.", score=".$score.", note='".$note."' WHERE user_email='".$user_email."'";
mysqli_close($con);
}else{
//echo "does not exist";
mysqli_query($con,"INSERT INTO rating(user_id, user_email, last_stage, score, note)VALUES (".$user_id.",'".$user_email."',".$last_stage.",".$score.",'".$note."') ");
mysqli_close($con);
}
?>
You can actually do it in a single query since MySQL has implemented INSERT ... ON DUPLICATE KEY UPDATE which basically INSERTs a record if it does not exists otherwise UPDATEs it.
The first thing you need to do is to add a UNIQUE column on the table. In your example I see that user_email is the column you are searching for existence. If this is not unique, you need to alter the table for UNIQUE constraint
ALTER TABLE rating ADD CONSTRAINT tb_uq UNIQUE(user_email)
after it has been implement, build a query like this,
INSERT INTO rating(user_id, user_email, last_stage, score, note)
VALUES($user_id, '$user_email', last_stage, score, '$note')
ON DUPLICATE KEY UPDATE
user_id = $user_id,
last_stage = $last_stage,
score = $score,
note= '$note'
As a sidenote, the query is vulnerable with SQL Injection if the value(s) of the variables came from the outside. Please take a look at the article below to learn how to prevent from it. By using PreparedStatements you can get rid of using single quotes around values.
How to prevent SQL injection in PHP?
$user_email="user_email";
should be changed to
$user_email=$_POST['user_email'];
And missing ( simbol, as #Yogesh Suthar said. You should also consider escaping characters in strings, using i.e. mysql_real_escape_string function.
you forgot ) here
mysqli_query($con,"UPDATE rating SET user_id=".$user_id.", user_email='".$user_email."', last_stage=".$last_stage.", score=".$score.", note='".$note."'
WHERE user_email='".$user_email."'");
^ // here
Better way is to use
REPLACE INTO `rating` (user_id,user_email,last_stage,score,note)
VALUES(#user_id,#user_email,#last_stage,#score,#note) WHERE user_email=#email
use also binding and prepared statements to make it more secure. Your code is very insecure because you have nor escape functions neither casting.
Example of using binding with PHP. $dbh is PDO object.
$stmt = $dbh->prepare("REPLACE INTO `rating` (user_id,user_email,last_stage,score,note)
VALUES(#user_id,#user_email,#last_stage,#score,#note) WHERE user_email=#email");
$stmt->bindParam('#name', (int)$user_id);
$stmt->bindParam('#user_email', $user_email);
$stmt->bindParam('#last_stage', $last_stage);
$stmt->bindParam('#score', $score);
$stmt->bindParam('#note', $note);
more on http://pl1.php.net/pdo
with binding you don't have to escape strings because it goes straight into the database layer without it having to be crudely spliced into the SQL statement.
The MySQL REPLACE statement works like the INSERT statement with the additional rules:
If the record which you want to insert does not exist, the MySQL REPLACE inserts a new record.
If the record which you want to insert already exists, MySQL REPLACE deletes the old record first and then insert a new record.
$user_email="user_email"; should be $user_email=$_POST["user_email"];

Categories