Question

I'm currently in the process of finishing a PHP script which parses emails and inserts them into database tables structured like so -

Users table

  • userId - int - auto_increment - PK
  • email - varchar

Emails table

  • emailId - int - auto_increment - PK
  • userId - int - FK
  • attachmentId - int - FK
  • body - varchar
  • subject - varchar

Attachments table

  • attachmentId - int - auto_increment - PK
  • attachmentName - varchar
  • fileType - varchar
  • content - mediumblob
  • code - varchar

My problem is that once I have parsed the email, how do I ensure that my foreign key relationships are correct? My initial approach was just to perform:

INSERT INTO users (email) values ('$emailFrom');
INSERT INTO emails (subject, body) values ('$subject', '$body');
INSERT INTO attachments (attachmentName, fileType, content, code) values ('$attachmentName', '$fileType', '$content', '$code');

but then I realised that this won't deal with my FK relationships in the emails table. Is the best approach to perform each query individually, re-query for the generated Id then place the new Id in the related FK row? Sorry if I'm not being clear.

Would there be any shortcomings in making this into one table and avoiding this problem?

Was it helpful?

Solution

I would recommend using a transaction, ensuring that the totality of the inserts is treated as atomic (one insert). This protects your data in the case that if one of the queries fail, your data doesn't end up in a malformed state.

Your code didn't elude to the type of API you are using (mysql, mysqli, pdo), but I will give a snippet using PDO (untested):

<?php 
try {

    $dbo = new PDO('mysql:host=localhost;dbname=test', 'username', 'password'); 

    $stmt1 = $dbo->prepare('INSERT INTO users SET email = :email'); 
    $stmt2 = $dbo->prepare('INSERT INTO attachments SET attachment_name = :attachmentName, file_type = :fileType');
    $stmt3 = $dbo->prepare('INSERT INTO emails SET set user_id = :userId, subject = :subject, body = :body, attachment_id = :attachmentId');

    try { 

        $dbo->beginTransaction(); 

        $stmt1->bindParam(':email', $email, PDO::PARAM_STR);
        $stmt->execute();

        $userId = $dbo->lastInsertId();

        $stmt2->bindParam(':attachmentName', $attachmentName, PDO::PARAM_STR);
        $stmt2->bindParam(':fileType', $fileType, PDO::PARAM_STR);
        $stmt2->execute();

        $attachmentId = $dbo->lastInsertId();

        $stmt3->bindParam(':userId', $userId, PDO::PARAM_INT);
        $stmt3->bindParam(':subject', $subject, PDO::PARAM_STR);
        $stmt3->bindParam(':body', $body, PDO::PARAM_STR);
        $stmt3->bindParam(':attachmentId', $attachmentId, PDO::PARAM_INT);
        $stmt3->execute();

        $dbo->commit(); 

    } catch(Exception $e) { 
        $dbo->rollback(); 
        error_log($e->getMessage()); 
    } 
} catch(Exception $e) { 
    error_log($e->getMessage());
} 

?>

You can read more about API calls used in the snippet using these links:

OTHER TIPS

First check to see if the $emailFrom exists in the users table, get the userid into $userid. If it doesn't exist then insert it and get the new userid into $userid.

Then insert into attachments and get the new attachmentid store in $attachmentID.

Then finally insert into emails:

 INSERT INTO emails (userid, attachmentid, subject, body) 
             values ($userid, $attachmentId, '$subject', '$body');

Then your foreign keys will be set up correctly.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top