DROP, TRUNCATE and DELETE Compared
Three ways to remove data, with very different consequences. Learn what each one destroys, what can be rolled back and what resets identity counters.
- SQL Basics
- DDL
- DML
- SELECT
- WHERE
- Functions
- NULL and Logic
- Aggregate Functions
- GROUP BY
- JOIN
- Subqueries
- Set Operations
- CTEs
- Constraints
- Keys
- Relationships
- Database Design
- Normalisation
- Views
- Window Functions
- Advanced SQL
- Procedures and Functions
- Triggers
- Temporary Tables
- Transactions
- Isolation and Locking
- Indexes
- Query Performance
- SQL Security
- SQL Dialects
- Practical SQL
Concept
Three statements remove data and they are constantly confused, because the difference is not in what you see afterwards but in what is left behind.
DELETE | TRUNCATE | DROP | |
|---|---|---|---|
| Type | DML | DDL | DDL |
| Removes | Chosen rows | All rows | The whole table |
| Table survives | Yes | Yes | No |
Has a WHERE | Yes | No | No |
| Fires triggers | Yes | No | No |
| Rollback | Yes, inside a transaction | No in MySQL and Oracle; yes in PostgreSQL and SQL Server | Same as TRUNCATE |
| Resets identity | No | Usually yes | Not applicable |
| Speed on a big table | Slow, row by row and logged | Fast, deallocates storage | Fast |
Syntax
DELETE FROM table_name WHERE condition;
TRUNCATE TABLE table_name;
DROP TABLE table_name;
DROP TABLE IF EXISTS table_name;
DROP VIEW view_name;
DROP INDEX index_name ON table_name; -- MySQL syntax
DROP DATABASE database_name;Example
-- Remove a subset, reversibly
START TRANSACTION;
DELETE FROM orders WHERE status = 'cancelled' AND order_date < '2023-01-01';
-- inspect the row count, then decide
ROLLBACK; -- or COMMIT;
-- Empty a staging table before a fresh load
TRUNCATE TABLE staging_orders;
-- Remove an object that is no longer part of the schema
DROP TABLE IF EXISTS staging_orders_old;Explanation
DELETE walks the rows, writes each removal to the log and fires triggers, which is why it is slow but also why it can be rolled back and audited. TRUNCATE throws away the table's data pages wholesale - far faster, but it cannot report which rows went, cannot fire row triggers and in MySQL cannot be undone because it is DDL and auto commits.
DROP removes the definition too. Afterwards the table does not exist, along with its indexes, triggers and privileges.
Important rules
TRUNCATEis refused on a table referenced by a foreign key in MySQL, PostgreSQL and SQL Server.DELETEis allowed and will enforce or cascade the constraint.- In MySQL and Oracle,
TRUNCATEandDROPauto commit. Wrapping them in a transaction gives no protection. - PostgreSQL allows
TRUNCATEinside a transaction and can roll it back. TRUNCATEnormally resets the auto increment or identity counter to its seed;DELETEnever does.DROP DATABASEremoves every object it contains, with no confirmation.
Common mistakes
- Running
DELETE FROM orders;with noWHERE. Every row goes. - Reaching for
TRUNCATEto "clean up a bit of test data" on a table with a foreign key and getting a confusing error. - Assuming a
TRUNCATEin MySQL can be rolled back because it was typed afterSTART TRANSACTION. - Expecting
TRUNCATEto fire an audit trigger. It does not.
Best practices
- Write the
WHEREclause first, run it as aSELECT, check the row count, and only then changeSELECT ...intoDELETE. - Enable safe updates while learning:
SET SQL_SAFE_UPDATES = 1;in MySQL refuses an unkeyedDELETEorUPDATE. - Take a backup before any
DROPin an environment you cannot rebuild. - Prefer a
deleted_atsoft delete column for business data that anyone might need to recover - exactly what this notes application itself does.
Practice
- Which statement would you use to empty a nightly import table, and why?
- Explain why
TRUNCATEcannot be used ondepartmentsin the sample schema. - Write the safe two step version of delete every inactive employee hired before 2019.