This question already has answers here:
if not exists insert in MySql
(2 answers)
Closed 9 years ago.
I'm a Java developer who just got handed the task of "some quick easy DB stuff" - except I don't know much about PHP/MySQL...I need to insert a record into a DB - but only if the email field doesn't match one that already exists in the DB. Here's what I've gleaned so far for my PHP code:
// Grab the values from the HTML form:
$newUserName = $_POST['newUserName'];
$newUserName = $mysqli->real_escape_string($newUserName);
$newUserEmail = $_POST['newUserEmail'];
$newUserEmail = $mysqli->real_escape_string($newUserEmail);
// Now search the DB to see if a record with this email already exists:
$mysqli->query("SELECT * FROM RegisteredUsersTable WHERE UserEmail = '$newUserEmail'");
Now I need to see if anything came back from that search - meaning the email already exists - and if so I need to alert the user, otherwise I can go ahead and insert the new info into the DB using:
$mysqli->query("INSERT INTO RegisteredUsersTable (UserName, UserEmail) VALUES ('".$newUserName."', '".$newUserEmail."')");
Any ideas?
Working from your code, this should point you in the right direction. there are, perhaps, better ways to structure your database that will make better use of it.
<?php
$mysqli = new mysqli("localhost", "iodine", "iodine","iodine");
// Grab the values from the HTML form:
/*
$newUserName = $_POST['newUserName'];
$newUserName = $mysqli->real_escape_string($newUserName);
$newUserEmail = $_POST['newUserEmail'];
$newUserEmail = $mysqli->real_escape_string($newUserEmail);
*/
$newUserName = "Test User";
$newUserEmail = "test4#example.com";
// Now search the DB to see if a record with this email already exists:
echo "SELECT * FROM RegisteredUsersTable WHERE UserEmail = '$newUserEmail'", "\n";
$result = $mysqli->query("SELECT * FROM RegisteredUsersTable WHERE UserEmail = '$newUserEmail'");
if (!$result) {
die($mysqli->error);
}
echo "num_rows = ".$result->num_rows."\n";
if ($result->num_rows > 0) {
echo "Duplicate email\n";
// do something to alert user about non-unique email
} else {
$result = $mysqli->query("INSERT IGNORE INTO RegisteredUsersTable (UserName, UserEmail) VALUES ('".$newUserName."', '".$newUserEmail."')");
if ($result === false) {echo "SQL error:".$mysqli->error;}
}
?>
Consider putting a unique index on this particular table. The following code will add the index and remove any current duplicates:
ALTER IGNORE TABLE `RegisteredUsersTable` ADD UNIQUE INDEX unique_email (`UserEmail`);
Once this is added, use INSERT IGNORE or INSERT...ON DUPLICATE KEY UPDATE. They will only preform the insert if there is no duplicates.
$mysqli->query("INSERT IGNORE INTO RegisteredUsersTable (UserName, UserEmail) VALUES ('".$newUserName."', '".$newUserEmail."')");
Mysql will throw an error because the email is already in the database. However, the IGNORE command is telling the script to not pay any attention to errors for this query because, in this case, you expect it for a duplicate row.
Also, there is a way to alert your user with a failure or success message, even with INSERT IGNORE. Use MYSQL LAST_INSERT_ID(). If an ID was given, it was inserted. If not, then the email was already there (or there was another error).
As for your first query, to soften the load on servers, use count() instead.
$mysqli->query("SELECT count(*) FROM RegisteredUsersTable WHERE UserEmail = '$newUserEmail'");
This way, you can just check if you've gotten a result higher than 1. If the result is greater than 1, then the username exists (Since a row was returned).
To check the data returned, you need to simply execute the statement, then fetch the results. Part of the fun is learning, so here's the documentation
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 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
}
I cant quite think about how to do this with mysql and php. Basically I want to be able to submit data into a mysql database but before it is inserted, it will check to see if that entry already exists.
$guid=$_POST['guid'];
$name=$_POST['name'];
//Username
$user="webhost";
//Password
$pass="*******";
//IP To Host
$ip="***********";
//Database
$db="dayz2";
//Table
$table="whitelist";
//Database Connection
$con=#mysql_connect("$ip", "$user", "$pass")
or die(mysql_error());
//Select Database
$dbcon=#mysql_select_db($db, $con)
or die(mysql_error());
$dupesql = "SELECT * FROM $table where (name = '$name' AND guid = '$guid')";
$duperaw = mysql_query($dupesql);
if (mysql_num_rows($duberaw) > 0) {
echo "Entry Already Exists";
}
else {
//Query Data Into Whitelist Table
$sql="INSERT INTO $table (name, guid) VALUES ('$name', '$guid')";
//Submit Data into Whitelist Table
$result=#mysql_query($sql, $con) or die(mysql_error());
}
?>
You can do it in another way, instead of:
submit data into a mysql database but before it is inserted, it will
check to see if that entry already exists.
You can do:
INSERT data into a mysql database if not existed, else ignore them
Something like :
INSERT IGNORE INTO table
INSERT IGNORE INTO yourtablename
SET fieldname = 'blah'
,..
It depends what you are trying to do - what is the exact criteria for your query?
You have several options:
use INSERT IGNORE ... if you only want to insert new rows that don't have a duplicate primary key. See http://dev.mysql.com/doc/refman/5.5/en/insert.html.
use INSERT ... ON DUPLICATE KEY UPDATE to insert new rows and update rows where there is a primary key match.
See http://dev.mysql.com/doc/refman/5.5/en/insert-on-duplicate.html.
use a normal SQL SELECT ... to pull the results first before performing business logic on the results before deciding which to INSERT ... or UPDATE ... depending on your requirements.
It depends how you want to handle case when the entry exists.
I you want to throw some error then you can create table trigger for insert event and put some checks there, but it will be slow because every insert will do this check.
I am trying to use a database where the email can have multiple entries, but i would like to prevent duplicate entries. Currently i have:
<?php
"SELECT Notes, itemName from UserItems where email = '$email'";
if("itemName" == $name && "Notes" == $desc) {
echo "duplicate";
}
?>
But itemName and Notes need to become strings for my if statement to work
My insert function is lower in my code but ill post it
$insert = ("insert into UserItems (itemName, ItemNumber, email, Price, Notes) Value (\"$name\", \"$ItemNumber\", \"$email\", \"$price\", \"$desc\")");
Am I missing something here? I held off answering cause I thought this would be too obvious and my post would waste time -
<?php
// add actual db connection info here
$email = 'someon#somewhere.com';
$name = 'John';
$desc = 'Some Description';
$row = mysql_fetch_array(mysql_query("SELECT Notes, itemName from UserItems where email = '$email'"));
if($row['itemName'] == $name && $row['Notes'] == $desc) {
echo "duplicate";
}
?>
You never actually run a query or fetch the results. Or define the variables you're comparing against. Are they $_POST, $_GET, results of the last row or something?
What about counting the number of entries where email = '$email'?
Based off the conversation we had in the comments, it sounds like your best bet is to handle this functionality at the database layer, by adding a unique contraint across all three columns (email, itemName, notes). With this solution the database will not allow more than one row with the same value for all three columns.
The mysql command would be:
alter table <your_table> add unique (`email`, `itemName`, `notes`);
// Will be inserted/updated no problem
foo#bar.com, itemName1, notes1
foo#bar.com, itemName1, notes2
foo#bar.com, itemName2, notes1
// An error will be returned because this row already exists
foo#bar.com, itemName1, notes2
The only drawback is that writes to the database will more costly as all three columns (notes especially) will have to be considered for the unique constraint.
Your other option is to load all rows matching the email address, then step through each row searching for matches against itemname and notes, which will be even more painful.
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).