diff --git a/mod/data/backup/moodle2/backup_data_stepslib.php b/mod/data/backup/moodle2/backup_data_stepslib.php
index 691b059..2a154a9 100644
--- a/mod/data/backup/moodle2/backup_data_stepslib.php
+++ b/mod/data/backup/moodle2/backup_data_stepslib.php
@@ -58,7 +58,7 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
 
         $record = new backup_nested_element('record', array('id'), array(
             'userid', 'groupid', 'timecreated', 'timemodified',
-            'approved'));
+            'approved', 'replaces'));
 
         $contents = new backup_nested_element('contents');
 
@@ -109,6 +109,7 @@ class backup_data_activity_structure_step extends backup_activity_structure_step
 
         $record->annotate_ids('user', 'userid');
         $record->annotate_ids('group', 'groupid');
+        $record->annotate_ids('data_records', 'replaces');
 
         $rating->annotate_ids('scale', 'scaleid');
         $rating->annotate_ids('user', 'userid');
diff --git a/mod/data/backup/moodle2/restore_data_stepslib.php b/mod/data/backup/moodle2/restore_data_stepslib.php
index 15af06a..9aef4a1 100644
--- a/mod/data/backup/moodle2/restore_data_stepslib.php
+++ b/mod/data/backup/moodle2/restore_data_stepslib.php
@@ -102,6 +102,7 @@ class restore_data_activity_structure_step extends restore_activity_structure_st
         $data->userid = $this->get_mappingid('user', $data->userid);
         $data->groupid = $this->get_mappingid('group', $data->groupid);
         $data->dataid = $this->get_new_parentid('data');
+        $data->replaces = $this->get_mappingid('data_record', $data->replaces);
 
         // insert the data_records record
         $newitemid = $DB->insert_record('data_records', $data);
diff --git a/mod/data/db/install.xml b/mod/data/db/install.xml
index 58f086e..9ead7bc 100644
--- a/mod/data/db/install.xml
+++ b/mod/data/db/install.xml
@@ -81,7 +81,8 @@
         <FIELD NAME="dataid" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="groupid" NEXT="timecreated"/>
         <FIELD NAME="timecreated" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="dataid" NEXT="timemodified"/>
         <FIELD NAME="timemodified" TYPE="int" LENGTH="10" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timecreated" NEXT="approved"/>
-        <FIELD NAME="approved" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timemodified"/>
+        <FIELD NAME="approved" TYPE="int" LENGTH="4" NOTNULL="true" UNSIGNED="true" DEFAULT="0" SEQUENCE="false" PREVIOUS="timemodified" NEXT="replaces"/>
+	<FIELD NAME="replaces" TYPE="int" LENGTH="10" NOTNULL="false" UNSIGNED="false" SEQUENCE="false" PREVIOUS="approved"/>
       </FIELDS>
       <KEYS>
         <KEY NAME="primary" TYPE="primary" FIELDS="id" NEXT="dataid"/>
@@ -106,4 +107,4 @@
       </KEYS>
     </TABLE>
   </TABLES>
-</XMLDB>
\ No newline at end of file
+</XMLDB>
diff --git a/mod/data/db/upgrade.php b/mod/data/db/upgrade.php
index 1d85846..4c1de46 100644
--- a/mod/data/db/upgrade.php
+++ b/mod/data/db/upgrade.php
@@ -313,6 +313,16 @@ function xmldb_data_upgrade($oldversion) {
         upgrade_mod_savepoint(true, 2010100101, 'data');
     }
 
+    if ($oldversion < 2010120100) {
+        $table = new xmldb_table('data_records');
+        $field = new xmldb_field('replaces', XMLDB_TYPE_INTEGER, '10', null, null, null, null, 'approved');
+
+        if (!$dbman->field_exists($table, $field)) {
+            $dbman->add_field($table, $field);
+        }
+        upgrade_mod_savepoint(true, 2010120100, 'data');
+    }
+
     return true;
 }
 
diff --git a/mod/data/edit.php b/mod/data/edit.php
index 34aef3f..ecb02b7 100755
--- a/mod/data/edit.php
+++ b/mod/data/edit.php
@@ -158,35 +158,78 @@ if ($datarecord = data_submitted() and confirm_sesskey()) {
 
     if ($rid) {                                          /// Update some records
 
-        /// All student edits are marked unapproved by default
+        $copyid = false;
         $record = $DB->get_record('data_records', array('id'=>$rid));
+        if ($data->approval && !has_capability('mod/data:approve', $context) && $record->approved) {
+            // See if there is already an entry awaiting approval
+            $record = $DB->get_record('data_records', array('replaces'=>$rid));
 
-        /// reset approved flag after student edit
-        if (!has_capability('mod/data:approve', $context)) {
-            $record->approved = 0;
+            if (!$record) {
+                // Need to create an entry for approval
+                $copyid = data_add_record($data, $currentgroup, $rid);
+            }
         }
+        
+        if ($copyid) {
+            // Update the old record to be marked as updated by this one
+            $oldupdate = new stdClass;
+            $oldupdate->id = $rid;
+            $oldupdate->replaces = -$copyid; // Note the '-' sign
+            $DB->update_record('data_records',$oldupdate);
 
-        $record->groupid = $currentgroup;
-        $record->timemodified = time();
-        $DB->update_record('data_records', $record);
+            // Equivalent to creating a new record
 
-        /// Update all content
-        $field = NULL;
-        foreach ($datarecord as $name => $value) {
-            if (!in_array($name, $ignorenames)) {
-                $namearr = explode('_',$name);  // Second one is the field id
-                if (empty($field->field) || ($namearr[1] != $field->field->id)) {  // Try to reuse classes
-                    $field = data_get_field_from_id($namearr[1], $data);
+            /// Insert a whole lot of empty records to make sure we have them
+            $fields = $DB->get_records('data_fields', array('dataid'=>$data->id));
+            foreach ($fields as $field) {
+                $content->recordid = $copyid;
+                $content->fieldid = $field->id;
+                $DB->insert_record('data_content',$content);
+            }
+
+            /// For each field in the add form, add it to the data_content.
+            foreach ($datarecord as $name => $value){
+                if (!in_array($name, $ignorenames)) {
+                    $namearr = explode('_', $name);  // Second one is the field id
+                    if (empty($field->field) || ($namearr[1] != $field->field->id)) {  // Try to reuse classes
+                        $field = data_get_field_from_id($namearr[1], $data);
+                    }
+                    if ($field) {
+                        $field->update_content($copyid, $value, $name);
+                    }
                 }
-                if ($field) {
-                    $field->update_content($rid, $value, $name);
+            }
+
+        } else {
+            /// All student edits are marked unapproved by default
+
+            /// reset approved flag after student edit
+            if (!has_capability('mod/data:approve', $context)) {
+                $record->approved = 0;
+            }
+
+            $record->groupid = $currentgroup;
+            $record->timemodified = time();
+            $DB->update_record('data_records', $record);
+
+            /// Update all content
+            $field = NULL;
+            foreach ($datarecord as $name => $value) {
+                if (!in_array($name, $ignorenames)) {
+                    $namearr = explode('_',$name);  // Second one is the field id
+                    if (empty($field->field) || ($namearr[1] != $field->field->id)) {  // Try to reuse classes
+                        $field = data_get_field_from_id($namearr[1], $data);
+                    }
+                    if ($field) {
+                        $field->update_content($rid, $value, $name);
+                    }
                 }
             }
         }
 
         add_to_log($course->id, 'data', 'update', "view.php?d=$data->id&amp;rid=$rid", $data->id, $cm->id);
 
-        redirect($CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&rid='.$rid);
+        redirect($CFG->wwwroot.'/mod/data/view.php?d='.$data->id.'&rid='.($copyid ? $copyid : $rid));
 
     } else { /// Add some new records
 
diff --git a/mod/data/lib.php b/mod/data/lib.php
index a22aa6b..684ee16 100755
--- a/mod/data/lib.php
+++ b/mod/data/lib.php
@@ -782,7 +782,7 @@ function data_numentries($data){
  * @param int $groupid
  * @return bool
  */
-function data_add_record($data, $groupid=0){
+function data_add_record($data, $groupid=0, $replaces=NULL){
     global $USER, $DB;
 
     $cm = get_coursemodule_from_instance('data', $data->id);
@@ -792,12 +792,18 @@ function data_add_record($data, $groupid=0){
     $record->userid = $USER->id;
     $record->dataid = $data->id;
     $record->groupid = $groupid;
-    $record->timecreated = $record->timemodified = time();
+    if ($replaces !== NULL) {
+        $record->timecreated = $DB->get_field('data_records','timecreated',array('id'=>$replaces));
+        $record->timemodified = time();
+    } else {
+        $record->timecreated = $record->timemodified = time();
+    }
     if (has_capability('mod/data:approve', $context)) {
         $record->approved = 1;
     } else {
         $record->approved = 0;
     }
+    $record->replaces = $replaces;
     return $DB->insert_record('data_records', $record);
 }
 
diff --git a/mod/data/rsslib.php b/mod/data/rsslib.php
index 7020d38..c3d63a4 100644
--- a/mod/data/rsslib.php
+++ b/mod/data/rsslib.php
@@ -107,7 +107,7 @@
             $time = '';
         }
 
-        $approved = ($data->approval) ? ' AND dr.approved = 1 ' : ' ';
+        $approved = ($data->approval) ? ' AND dr.approved = 1 ' : ' AND (dr.replaces IS NULL OR dr.replaces > 0) ';
 
         $sql = "SELECT dr.*, u.firstname, u.lastname
                   FROM {data_records} dr, {user} u
diff --git a/mod/data/version.php b/mod/data/version.php
index b57666a..0cc3c8c 100644
--- a/mod/data/version.php
+++ b/mod/data/version.php
@@ -5,7 +5,7 @@
 //  This fragment is called by /admin/index.php
 ////////////////////////////////////////////////////////////////////////////////
 
-$module->version  = 2010100101;
+$module->version  = 2010120100;
 $module->requires = 2010080300;  // Requires this Moodle version
 $module->cron     = 60;
 
diff --git a/mod/data/view.php b/mod/data/view.php
index 818bceb..4ec3364 100755
--- a/mod/data/view.php
+++ b/mod/data/view.php
@@ -334,6 +334,22 @@
         if ($confirm = optional_param('confirm',0,PARAM_INT)) {
             if ($deleterecord = $DB->get_record('data_records', array('id'=>$delete))) {   // Need to check this is valid
                 if ($deleterecord->dataid == $data->id) {                       // Must be from this database
+                    
+                    if ($deleterecord->replaces > 0) {
+                        // This is an unapproved update, so user would expect the original to be deleted as well
+                        $originalrecord = $DB->get_record('data_records', array('id'=>$deleterecord));
+                        
+                        if ($contents = $DB->get_records('data_content', array('recordid'=>$originalrecord->id))) {
+                            foreach ($contents as $content) {  // Delete files or whatever else this field allows
+                                if ($field = data_get_field_from_id($content->fieldid, $data)) { // Might not be there
+                                    $field->delete_content($content->recordid);
+                                }
+                            }
+                        }
+                        $DB->delete_records('data_content', array('recordid'=>$originalrecord->id));
+                        $DB->delete_records('data_records', array('id'=>$originalrecord->id));
+                    }
+
                     if ($contents = $DB->get_records('data_content', array('recordid'=>$deleterecord->id))) {
                         foreach ($contents as $content) {  // Delete files or whatever else this field allows
                             if ($field = data_get_field_from_id($content->fieldid, $data)) { // Might not be there
@@ -404,11 +420,51 @@ if ($showactivity) {
 
         if ($approve && confirm_sesskey() && $approvecap) {
             if ($approverecord = $DB->get_record('data_records', array('id'=>$approve))) {   // Need to check this is valid
-                if ($approverecord->dataid == $data->id) {                       // Must be from this database
-                    $newrecord = new stdClass();
-                    $newrecord->id = $approverecord->id;
-                    $newrecord->approved = 1;
-                    $DB->update_record('data_records', $newrecord);
+
+                if (!$approverecord->replaces) {
+                    if ($approverecord->dataid == $data->id) {                       // Must be from this database
+                        $newrecord = new stdClass();
+                        $newrecord->id = $approverecord->id;
+                        $newrecord->approved = 1;
+                        $DB->update_record('data_records', $newrecord);
+                    }
+
+                } else { // This record was replacing another record
+                    // Delete the old content that this replaced
+                    if ($oldrecord = $DB->get_record('data_records', array('id'=>$approverecord->replaces))) {   // Need to check this is valid
+                        if ($oldrecord->dataid == $data->id) {                       // Must be from this database
+                            if ($contents = $DB->get_records('data_content', array('recordid'=>$oldrecord->id))) {
+                                foreach ($contents as $content) {  // Delete files or whatever else this field allows
+                                    if ($field = data_get_field_from_id($content->fieldid, $data)) { // Might not be there
+                                        $field->delete_content($content->recordid);
+                                    }
+                                }
+                            }
+                            $DB->delete_records('data_content', array('recordid'=>$oldrecord->id));
+
+                            // Now point all the new content at the old record
+                            $newcontents = $DB->get_records('data_content', array('recordid'=>$approverecord->id));
+                            foreach ($newcontents as $content) {
+                                $updatecontent = new stdClass();
+                                $updatecontent->id = $content->id;
+                                $updatecontent->recordid = $oldrecord->id;
+                                $DB->update_record('data_content', $updatecontent);
+                            }
+
+                            // Delete the new record
+                            $DB->delete_records('data_records', array('id'=>$approverecord->id));
+                            
+                            // Update the old record to no longer be marked as 'replaced'
+                            $updateold = new stdClass;
+                            $updateold->id = $oldrecord->id;
+                            $updateold->replaces = NULL;
+                            $DB->update->record('data_records', $updateold);
+
+                            if ($record && $record->id == $approverecord->id) {
+                                $record = $oldrecord;
+                            }
+                        }
+                    }
                     echo $OUTPUT->notification(get_string('recordapproved','data'), 'notifysuccess');
                 }
             }
@@ -432,15 +488,19 @@ if ($showactivity) {
         }
 
     /// setup group and approve restrictions
+
         if (!$approvecap && $data->approval) {
             if (isloggedin()) {
-                $approveselect = ' AND (r.approved=1 OR r.userid=:myid1) ';
+                $approveselect = ' AND ((r.userid!=:myid1 AND r.approved=1) OR (r.userid=:myid2 AND (r.approved=0 OR r.replaces IS NULL OR r.replaces > 0))) ';
+                // Not mine => see all approved; mine => hide approved entries that have pending replacements
                 $params['myid1'] = $USER->id;
+                $params['myid2'] = $USER->id;
             } else {
                 $approveselect = ' AND r.approved=1 ';
             }
         } else {
-            $approveselect = ' ';
+            $approveselect = ' AND (r.approved=0 OR r.replaces IS NULL OR r.replaces > 0) '; // Hide approved entries which have pending replacements from teachers
+            // (they will see the pending replacement record instead)
         }
 
         if ($currentgroup) {
@@ -571,6 +631,7 @@ if ($showactivity) {
         $sqlselect  = "SELECT $what $fromsql $sortorder";
         $sqlcount   = "SELECT $count $fromsql";   // Total number of records when searching
         $sqlmax     = "SELECT $count FROM $tables $where $groupselect $approveselect"; // number of all recoirds user may see
+        
         $allparams  = array_merge($params, $advparams);
 
     /// Work out the paging numbers and counts
