The SQL DELETE command removes rows from a table. Use a WHERE clause when only selected records should be deleted.
DELETE FROM student
WHERE mark < 60;
This removes only students whose mark value is below 60.
SELECT id, name, mark
FROM student
WHERE mark < 60;
DELETE FROM table_name
WHERE condition;
The WHERE condition decides which rows are removed.
Example: delete one student by ID.
DELETE FROM student
WHERE id = 10;
When an ID uniquely identifies a record, this normally removes at most one row.
A practical safety habit is to test the condition with SELECT first.
SELECT id, name, class, mark
FROM student
WHERE class = 'Four';
After confirming the result, use the same condition with DELETE:
DELETE FROM student
WHERE class = 'Four';
This is safer than writing a destructive condition and executing it without first checking which records match.
DELETE FROM student
WHERE mark < 60;
DELETE FROM student
WHERE class = 'Four'
AND mark < 60;
DELETE FROM student
WHERE class IN ('Four', 'Five');
See AND / OR conditions and IN for deeper filtering examples.
A DELETE statement without a WHERE clause removes every row while leaving the table structure in place.
DELETE FROM student;
MySQL also supports TRUNCATE when the goal is specifically to empty a whole table:
TRUNCATE TABLE student;
DELETE and TRUNCATE are not interchangeable in every situation. Their transaction, trigger, foreign-key and AUTO_INCREMENT behavior differs.
MySQL supports multi-table DELETE statements. Suppose student contains one student record and student_fee contains related fee records for the same ID.
To remove matching records from both tables for student ID 2:
DELETE student, student_fee
FROM student
INNER JOIN student_fee
ON student.id = student_fee.id
WHERE student.id = 2;
This removes the matching row from student and all matching rows from student_fee.
To remove all rows that match in both tables:
DELETE student, student_fee
FROM student
INNER JOIN student_fee
ON student.id = student_fee.id;
The following MySQL example works with three linked tables used by the Plus2net country, state and city dropdown example.
DELETE FROM plus2_country, plus2_state, plus2_city
USING plus2_country
INNER JOIN plus2_state
ON plus2_country.country_code = plus2_state.country_code
INNER JOIN plus2_city
ON plus2_state.state_id = plus2_city.state_id
WHERE plus2_country.country_code = 'CAN';
The query removes Canada from plus2_country, its matching states from plus2_state, and matching cities from plus2_city.
dropdown3.sql remains available with the downloadable source used by that example.Suppose we want to remove students who have no matching row in student_fee.
DELETE student
FROM student
LEFT JOIN student_fee
ON student_fee.id = student.id
WHERE student_fee.id IS NULL;
See the LEFT JOIN tutorial for the matching logic.
DELETE FROM student
WHERE NOT EXISTS (
SELECT 1
FROM student_fee
WHERE student_fee.id = student.id
);
NOT EXISTS is often a clear choice for this type of anti-match condition. See SQL subqueries.
DELETE FROM student
WHERE id NOT IN (
SELECT id
FROM student_fee
WHERE id IS NOT NULL
);
NOT IN needs extra care when the subquery can return NULL. A NULL in the list can change the result of the comparison. NOT EXISTS avoids that particular problem.For a single-table DELETE, MySQL can combine DELETE with ORDER BY and LIMIT.
DELETE FROM student
WHERE mark < 40
ORDER BY id
LIMIT 5;
This removes at most five matching rows, starting with the lowest IDs according to the stated ordering.
Using ORDER BY is important when the specific rows removed by LIMIT must be predictable. See ORDER BY and LIMIT.
A DELETE can fail when another table references the row through a foreign key.
Depending on the schema, the relationship can be configured to reject the delete or to remove related child rows automatically with ON DELETE CASCADE.
For transactional MySQL tables such as InnoDB, DELETE is a data-modification statement that can participate in a transaction.
START TRANSACTION;
DELETE FROM student
WHERE id = 10;
ROLLBACK;
Before the transaction is committed, a rollback can undo the DELETE. Once committed, recovery requires another data source such as a backup or application history.
This differs from MySQL DDL operations such as normal TRUNCATE and DROP TABLE, which have implicit-commit behavior.
| Command | Removes | WHERE | Table remains | Typical use |
|---|---|---|---|---|
| DELETE | Selected or all rows | Yes | Yes | Remove row data selectively |
| TRUNCATE | All rows | No | Yes | Empty a complete table |
| DROP | Rows and table definition | No | No | Remove the table itself |
DELETE FROM student
WHERE class = 'Four';
Deletes matching rows and keeps the table.
TRUNCATE TABLE student;
Empties the table. In MySQL, TRUNCATE also resets AUTO_INCREMENT for the table and has DDL-like implicit-commit behavior.
DROP TABLE student;
Removes the table itself, including its stored rows and definition.
When the condition contains an external value, use a prepared PDO statement instead of concatenating the value into SQL.
<?php
require 'config.php';
$id=10;
$sql="DELETE FROM student
WHERE id=:id";
$stmt=$dbo->prepare($sql);
$stmt->bindValue(':id',$id,PDO::PARAM_INT);
$stmt->execute();
$deleted=$stmt->rowCount();
echo 'Rows deleted: '.$deleted;
See the PHP PDO DELETE tutorial for input validation, POST confirmation, transactions and application-level safety.
MySQL reports the number of rows affected by DELETE. In PDO, rowCount() can be used after the DELETE statement:
$deleted=$stmt->rowCount();
echo 'Rows deleted: '.$deleted;
At the MySQL level, affected-row information is also covered in MySQL affected rows.
DELETE FROM student; is valid SQL and removes every row. Always verify whether a condition is required.
For important data, run SELECT with the same WHERE clause first so you can see exactly which rows match.
If the subquery can return NULL, NOT IN may not behave as expected. Filter NULLs explicitly or consider NOT EXISTS.
Deleting rows does not normally reset the table's AUTO_INCREMENT sequence. TRUNCATE has different behavior in MySQL.
Related child rows can block a DELETE or be removed automatically depending on the foreign-key action defined in the schema.
Use prepared statements for external values. Prepared statements do not replace validation, authorization or CSRF protection in an application.
The multi-table examples on this page use MySQL syntax. Other database systems can use different DELETE syntax.
Use DELETE FROM table_name with a WHERE condition that uniquely identifies the required row, such as WHERE id=10.
All rows in the table are deleted, but the table definition remains.
DELETE can remove selected rows with WHERE and participates in normal data transactions for transactional tables. TRUNCATE removes all rows and has different MySQL behavior, including AUTO_INCREMENT reset and implicit commit.
For a transactional table such as InnoDB, a DELETE inside an uncommitted transaction can be rolled back. After commit, rollback no longer restores the rows.
MySQL supports multi-table DELETE syntax, allowing named target tables to be deleted through a JOIN condition.
A related child row can reference the record being deleted. The foreign-key definition determines whether the delete is rejected or related rows are removed automatically.
MySQL returns an affected-row count. With PHP PDO, PDOStatement::rowCount() can report the number of rows deleted by the statement.
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.