To add a MySQL record with PDO, prepare an INSERT query, bind the values and execute the statement. If the table uses an auto-increment ID, lastInsertId() can return the ID generated for the new record.
<?php
require 'config.php';
$name='Alex R';
$class='Five';
$mark=70;
$gender='Female';
$sql="INSERT INTO student
(name,class,mark,gender)
VALUES
(:name,:class,:mark,:gender)";
try{
$stmt=$dbo->prepare($sql);
$stmt->bindValue(
':name',
$name,
PDO::PARAM_STR
);
$stmt->bindValue(
':class',
$class,
PDO::PARAM_STR
);
$stmt->bindValue(
':mark',
$mark,
PDO::PARAM_INT
);
$stmt->bindValue(
':gender',
$gender,
PDO::PARAM_STR
);
$stmt->execute();
$new_id=$dbo->lastInsertId();
echo 'Record added. Student ID: '.$new_id;
}catch(PDOException $e){
error_log($e->getMessage());
echo 'Unable to add the record.';
}
The PDO connection object $dbo is created in the config.php connection file.
The SQL INSERT statement adds a new row to a table. In PDO, placeholders can be used instead of placing PHP variable values directly inside the SQL.
$sql="INSERT INTO student
(name,class,mark,gender)
VALUES
(:name,:class,:mark,:gender)";
$stmt=$dbo->prepare($sql);
The values are supplied separately:
$stmt->bindValue(
':name',
$name,
PDO::PARAM_STR
);
$stmt->bindValue(
':mark',
$mark,
PDO::PARAM_INT
);
$stmt->execute();
This keeps supplied data separate from the SQL statement.
Values submitted through an HTML form can be collected with $_POST and validated before the INSERT is executed.
$name=trim($_POST['name'] ?? '');
$class=trim($_POST['class'] ?? '');
$gender=trim($_POST['gender'] ?? '');
$mark=filter_input(
INPUT_POST,
'mark',
FILTER_VALIDATE_INT
);
See the PHP form tutorials for collecting and processing form values.
Prepared statements keep supplied values separate from SQL syntax, but application data should still be validated before it is stored.
if(
$name==='' ||
$class==='' ||
$gender==='' ||
$mark===false ||
$mark<0 ||
$mark>100
){
exit('Please enter valid student data.');
}
Validation checks whether values are acceptable for the application. PDO parameter binding protects the structure of the SQL query. These are separate tasks.
A more complete form with validation is available in the PHP signup tutorial.
When the table uses an auto-increment field, MySQL generates a new ID while inserting the record.
After the INSERT succeeds, call lastInsertId() on the PDO connection:
$stmt->execute();
$new_id=$dbo->lastInsertId();
echo 'New student ID: '.$new_id;
Example:
New student ID: 37
lastInsertId() belongs to the PDO connection object $dbo. Methods such as execute() and rowCount() belong to the PDO statement.See the MySQL insert ID tutorial for more about retrieving the generated ID.
Parameters can also be supplied as an array when the prepared statement is executed.
$sql="INSERT INTO student
(name,class,mark,gender)
VALUES
(:name,:class,:mark,:gender)";
$stmt=$dbo->prepare($sql);
$stmt->execute([
':name' => 'Alice',
':class' => 'Five',
':mark' => 95,
':gender' => 'Female'
]);
$new_id=$dbo->lastInsertId();
echo 'Student ID: '.$new_id;
When the parameter type should be specified explicitly, such as for an integer, use bindValue() with the corresponding PDO parameter type.
When several rows use the same INSERT structure, prepare the statement once and execute it repeatedly with different values.
$students=[
[
'name' => 'Bob',
'class' => 'Six',
'mark' => 89,
'gender' => 'Male'
],
[
'name' => 'Charlie',
'class' => 'Seven',
'mark' => 76,
'gender' => 'Female'
]
];
$sql="INSERT INTO student
(name,class,mark,gender)
VALUES
(:name,:class,:mark,:gender)";
$stmt=$dbo->prepare($sql);
foreach($students as $student){
$stmt->bindValue(
':name',
$student['name'],
PDO::PARAM_STR
);
$stmt->bindValue(
':class',
$student['class'],
PDO::PARAM_STR
);
$stmt->bindValue(
':mark',
$student['mark'],
PDO::PARAM_INT
);
$stmt->bindValue(
':gender',
$student['gender'],
PDO::PARAM_STR
);
$stmt->execute();
echo 'Student ID: '.$dbo->lastInsertId().'<br>';
}
Example output:
Student ID: 40
Student ID: 41
If several related records must all be inserted successfully, use a PDO transaction. If one operation fails, the completed inserts can be rolled back.
$students=[
[
'name' => 'John Doe',
'class' => 'Six',
'mark' => 85,
'gender' => 'Male'
],
[
'name' => 'Jane Doe',
'class' => 'Seven',
'mark' => 90,
'gender' => 'Female'
]
];
$sql="INSERT INTO student
(name,class,mark,gender)
VALUES
(:name,:class,:mark,:gender)";
try{
$dbo->beginTransaction();
$stmt=$dbo->prepare($sql);
foreach($students as $student){
$stmt->bindValue(
':name',
$student['name'],
PDO::PARAM_STR
);
$stmt->bindValue(
':class',
$student['class'],
PDO::PARAM_STR
);
$stmt->bindValue(
':mark',
$student['mark'],
PDO::PARAM_INT
);
$stmt->bindValue(
':gender',
$student['gender'],
PDO::PARAM_STR
);
$stmt->execute();
}
$dbo->commit();
echo 'Records inserted successfully.';
}catch(Throwable $e){
if($dbo->inTransaction()){
$dbo->rollBack();
}
error_log($e->getMessage());
echo 'Unable to insert the records.';
}
PDO Transactions and Rollback
A database constraint, duplicate unique value or invalid database operation can cause an INSERT to fail.
try{
$stmt=$dbo->prepare($sql);
$stmt->execute();
$new_id=$dbo->lastInsertId();
}catch(PDOException $e){
error_log($e->getMessage());
echo 'Unable to add the record.';
}
errorInfo() output to visitors on a production site. Log the detailed error on the server instead.if($mark<0 || $mark>100){
exit('Mark must be between 0 and 100.');
}
Application validation should normally happen before sending the INSERT statement to MySQL.
Dates stored in MySQL should use a format supported by the target date column. The SQL section has more examples on inserting date values into MySQL.
For a MySQL DATE column, PHP can create a value in Y-m-d format:
$dt=date('Y-m-d');
$sql="INSERT INTO table_name
(dt)
VALUES
(:dt)";
$stmt=$dbo->prepare($sql);
$stmt->bindValue(
':dt',
$dt,
PDO::PARAM_STR
);
$stmt->execute();
$date=new DateTime($dt);
$dt=$date->format('Y-m-d');
Validate user-entered dates before storing them in the database.
If the database column permits SQL NULL values and no date is available, bind a PHP null using PDO::PARAM_NULL.
$dt=null;
$stmt=$dbo->prepare(
"INSERT INTO table_name
(dt)
VALUES
(:dt)"
);
$stmt->bindValue(
':dt',
$dt,
PDO::PARAM_NULL
);
$stmt->execute();
$dt=trim($_POST['dt'] ?? '');
if($dt===''){
$dt=null;
}else{
$date=DateTimeImmutable::createFromFormat(
'!Y-m-d',
$dt
);
$errors=DateTimeImmutable::getLastErrors();
if(
$date===false ||
(
$errors!==false &&
(
$errors['warning_count']>0 ||
$errors['error_count']>0
)
)
){
exit('Invalid date.');
}
$dt=$date->format('Y-m-d');
}
$stmt=$dbo->prepare(
"INSERT INTO table_name
(dt)
VALUES
(:dt)"
);
$stmt->bindValue(
':dt',
$dt,
$dt===null ? PDO::PARAM_NULL : PDO::PARAM_STR
);
$stmt->execute();
The prepared-statement approach can also be used with PDO SQLite. The PDO interface is similar, although connection details and database-specific SQL can differ.
Insert HTML Form Data using PDO SQLite and MySQL
Avoid constructing the INSERT query by joining external values into the SQL. Use placeholders and prepared statements.
lastInsertId() belongs to the PDO connection:
$new_id=$dbo->lastInsertId();
Log technical database exceptions and show a short message instead of exposing SQL or database details.
Prepared statements protect the SQL structure, but they do not decide whether a name, mark, date or other value is valid for the application.
If all inserts must succeed together, use a transaction so completed inserts can be rolled back if a later operation fails.
Use a PHP null value together with PDO::PARAM_NULL when the database column should receive SQL NULL.
Download the complete sample scripts from the main PDO tutorial.
Sample Student Table SQL DumpPrepare an INSERT statement containing placeholders, bind or supply the values separately and call execute() on the PDOStatement.
Prepared statements keep supplied values separate from the SQL statement and allow values to be bound using the expected parameter type.
After the INSERT succeeds, call lastInsertId() on the PDO connection object.
Yes. Prepare the INSERT once and execute it repeatedly with a new set of values for each record.
Use a transaction when several related inserts must either all succeed or all be rolled back together if an error occurs.
Use a PHP null value and bind it with PDO::PARAM_NULL when the database column permits NULL.
No. Prepared statements separate values from SQL syntax, while validation checks whether those values satisfy the application's rules.
Author & Instructor at plus2net
I write and maintain practical tutorials on Python, PHP, SQL, JavaScript, HTML, jQuery, and web development at plus2net. The tutorials focus on clear explanations, working examples, and code that readers can test and adapt while learning.