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
}
Related
I'm trying to validate and show a message to the user whenever a duplicate entry is submitted. Also, I am using this validation to generate an entry in my database whenever a user registers for the first time. I'm aware my code might be SQL Injection compromised, but I'm not worried about that in this exercise.
My table has a primary key "RUT", it is unique. I need to validate if the user is submitting a RUT already in the database.
Code:
$datos;
#$db = mysqli_connect("localhost","root","","speedomart");
if($db){
$sql = "insert into cliente values('".$rut."','".$nombre."','".$apellido."','".$correo."','".$pass."')";
$query = $db->prepare($sql);
$query ->execute();
if(mysql_errno() == 1062){
$datos = array('mensaje' => "no fue posible insertar datos");
echo json_encode($datos);
}
else{
$sql2 = "insert into carrito values(NULL,'".$rut."')";
$query = $db->prepare($sql2);
$query ->execute();
$datos = array('mensaje' => "Registrado correctamente");
echo json_encode($datos);
};
}
else{
$datos = array('mensaje' => "No hay conexion.");
echo json_encode($datos);
};
I am assuming that it is the email which can not be duplicate. So when you submit the form you can first select the data using the particular email id as follows:
$sql = "select *from table where email ='".$email."'";
$query = $db->prepare($sql);
$user_array = $query ->execute();
if(count($user_array) > 0){
//You can use insert query here
}else{
//email already exist.
}
Two comments:
(1) If "the nature of the data is" that there should be no duplicates for any field or particular combination of fields, then you should define a UNIQUE index so that SQL will never allow a duplicate to be inserted by any means. (You will not be able to create such an index if any duplicates now exist.) This is a "data integrity rule" which SQL will enforce for you.
(2) SQL injection is trivially easy to avoid here, and you should always do so. Simply use parameters in your SQL query text: ? (without quotation marks ... this not a one-character literal string). Now, you simply supply an array of parameter-value substitutions each time you execute the prepared SQL. The parameters will be substituted left-to-right in order of occurrence. This not only avoids injection problems but also is more efficient: the statement does not have to be re-prepared each time. Please just get in the habit of doing this all the time ... you'll be glad you did.
IF Exists(SELECT 1 FROM Table WHERE FieldValue='$') THEN
--record exists, get ID you need.
BEGIN
SELECT TableID FROM Table WHERE FieldValue='$';
END;
ELSE
BEGIN
INSERT INTO Table (FieldValue) VALUES('$');
SELECT LAST_INSERT_ID() AS TableID;
END;
END IF;
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);
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
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) {
....
}
Is there a way to retrieve the ID of a record (primary key) after an insert when the mysql error returns a duplicate key?
E.G. How I would go about it:
$sql = "INSERT INTO table (`col1`, `col2`) VALUES ('$val1', '$val2')";
$result = mysql_query($sql);
if($result){
$id = mysql_insert_id();
}
else {
if(stristr(mysql_error(), "duplicate"){
$sql = "SELECT `id` FROM `table` WHERE `col1`='$val1' AND `col2`='$val2'";
$result = mysql_query($sql);
$row = mysql_fetch_array($result);
$id = $row['id'];
}
else {
die(mysql_error());
}
}
Here I've had to do two sql statements which not only take time and effort, but duplicate code as well.
I cannot use ON DUPLICATE KEY UPDATE because I want to update a different table using the either the last inserted id, or the id of the record that cannot be duplicated.
So, am I right in what I'm doing? Or is there a way to get the id of the row?
Thanks
MySQL will not tell you which record holds the original value, you'll have to find out yourself. Here you are some tips:
Looking for the duplicate substring in the text of the error message does not look very robust. You can just test the value of mysql_errno() against the code for duplicate entry, which is 1062 (you can find all codes in the manual).
The mysql extension does not provide a mechanism to find out name of the violated key, so you'll have to use the non-robust approach of parsing the text of the error message:
if( preg_match("/Duplicate entry '.*' for key '(.*)'/Ui", mysql_error(), $matches) ){
$violated_key = $matches[1];
}else{
throw new Exception('Could not find violated key name');
}
Alternatively, just run a previous query (there's no reason to avoid it):
SELECT id
FROM table
WHERE col1=... AND col2=...
FOR UPDATE
The FOR UPDATE clause will lock matching rows to avoid race conditions (assuming InnoDB).