3
$DBH = new PDO($dsn, $username, $password, $opt);

$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$DBH->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$STH = $DBH->prepare("INSERT INTO requests (id,imdbid,msg) VALUES ('',:imdbid,:msg)");
$STH->bindParam(':imdbid', $_POST['imdbid']);
$STH->bindParam(':msg', $_POST['msg']);

$STH->execute();
echo "<p>Successfully Requested ".$_POST['imdbid']."! Thanks!</p>";

Is there either some SQL Query that will check and insert or what? I need it to check if whatever the user typed is already in the db so if the user typed in a imdbid that is already there then it wont continue inserting anything. How would I do this? I know I can do a fetch_all and make a foreach for it but doesnt that only work after you execute?

3 Answers 3

7

It's better to set a constraint on your columns to prevent duplicate data instead of checking and inserting.

Just set a UNIQUE constraint on imdbid:

ALTER TABLE `requests` ADD UNIQUE `imdbid_unique`(`imdbid`);

The reason for doing this is so that you don't run into a race condition.

There's a small window between finishing the check, and actually inserting the data, and in that small window, data could be inserted that will conflict with the to-be-inserted data.

Solution? Use constraints and check $DBH->error() for insertion errors. If there are any errors, you know that there's a duplicate and you can notify your user then.

I noticed that you are using this, $DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);. In this case, you don't need to check ->error() because PDO will throw an exception. Just wrap your execute with try and catch like this:

$duplicate = false;

try {
    $STH->execute();
} catch (Exception $e) {
    echo "<p>Failed to Request ".$_POST['imdbid']."!</p>";
    $duplicate = true;
}

if (!$duplicate)
    echo "<p>Successfully Requested ".$_POST['imdbid']."! Thanks!</p>";
Sign up to request clarification or add additional context in comments.

15 Comments

Hey again dave :P Anyway, why did u add imdbid, and msg together then _unique? I only want it to stop if the imdbid is already in the db but if the message is the same i dont mind. So lets say in my db i have: imdbid = 123 msg = Hey they enter in imdbid = 1234 msg = Hey it should still allow it to be inserted
Also when i add the unique what exactly happens? And do I then use INSERT INTO requests (id,imdbid_unique,msg_unique) ?
No problem, I've edited the code above to only set a UNIQUE constraint on imdbid alone. What happens next is that you just insert like you normally would, except you check errors from your database. If there is an error from $DBH->error(), then you know that you inserted duplicate data.
When i try to do the Alter Table SQL i get this: MySQL said: #1170 - BLOB/TEXT column 'imdbid' used in key specification without a key length
Can you change your datatype to an INT or VARCHAR? You can't place UNIQUE constraints on BLOB or TEXT. Also usually for an ID like an IMDB id, you wouldn't need TEXT or BLOB to hold it. TEXT is usually used for posts or comments.
|
2

Simply run a query prior to inserting.

If found die the script:

$DBH = new PDO($dsn, $username, $password, $opt);

$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$DBH->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$sql = 'SELECT COUNT(*) from requests WHERE imdbid = :imdbid';
$stmt = $DBH->prepare($sql);
$stmt->execute(array(':imdbid' => $_POST['imdbid']));

if($stmt->fetchColumn()){ die('Already exist');}

$STH = $DBH->prepare("INSERT INTO requests (id,imdbid,msg) VALUES ('',:imdbid,:msg)");
$STH->bindParam(':imdbid', $_POST['imdbid']);
$STH->bindParam(':msg', $_POST['msg']);

$STH->execute();
echo "<p>Successfully Requested ".$_POST['imdbid']."! Thanks!</p>";

or alternatively make the msg field unique.

Using a stored Procedure:

DELIMITER //
 CREATE PROCEDURE insert_request_msg(IN `p_imbd`, IN `p_msg`)
    IF NOT EXISTS (SELECT COUNT(*) from requests WHERE imdbid = p_imbd)
    BEGIN
        INSERT INTO requests (id,imdbid,msg) VALUES ('',p_imbd,p_msg)
    END
    END IF; //
 DELIMITER ;

You call it in one query like this:

$STH = $DBH->prepare('
call insert_request_msg(:imdbid,:msg)
');
$STH->bindParam(':imdbid', $_POST['imdbid']);
$STH->bindParam(':msg', $_POST['msg']);

12 Comments

Which would be faster, Your script or Daves? Im all about page load speed :P
It would not be a big speed difference you can notice but the issue with daves it creates an execption because it is an error to insert a duplicate, I added on more example to use a stored procedure to check of the row exist or not all in one query
Ok, I dont understand, Is the 2nd code block the WHOLE query in one? where would I place it that query if im putting call insert_request_msg(:imdbid,:msg) in the prepare()? Also do note, Im trying to get it to check if the imdbid is already in the database I could care less if the same message was used either on the same imdb or different ones.
oh ok I made it simpler now check my edit, you would run this whole block in mysql so that the stored procedure gets created then you will be able to run it in one query
Ok but remember, As I said, I dont care if the msg is unique or not I only care if the imdbid is already in the database Pleas can u update your code?
|
1

Try this

$DBH = new PDO($dsn, $username, $password, $opt);

$DBH->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$DBH->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

$STH = $DBH->prepare("INSERT INTO requests (id,imdbid,msg) VALUES ('',:imdbid,:msg) WHERE NOT EXISTS(SELECT imdbid FROM requests WHERE imdbid =:imdbid)");
$STH->bindParam(':imdbid', $_POST['imdbid']);
$STH->bindParam(':msg', $_POST['msg']);

$STH->execute();
echo "<p>Successfully Requested ".$_POST['imdbid']."! Thanks!</p>";

Source

2 Comments

Wouldnt that just add it and then just check if its not there?
I couldnt check its working. But it wont add with respect to SELECT, because that could return false. Can you check in realtime. If not, let me know.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.