Modules / Database / DDL Lab

DDL in SQL

Data Definition Language builds the shape of your database. Design a table column by column, watch the CREATE TABLE statement write itself, then ALTER, TRUNCATE and DROP it to see what happens to the data each time.

not created

DDL: Defining the Shape of Your Data

Before a single row can be stored, something has to declare what a row looks like. That is DDL's job.

Context first

Data Definition Language is the subset of SQL that creates and changes structure — tables, columns, types, constraints, indexes. It is distinct from DML, which changes the contents. A useful shorthand: DDL is the blueprint, DML is the furniture.

The Four Commands

  • CREATE — brings a new object into existence. Fails if it already exists (unless you write IF NOT EXISTS).
  • ALTER — changes an existing object: add a column, drop a column, change a type, add a constraint. Existing rows are adjusted to fit.
  • TRUNCATE — removes all rows but keeps the table. Faster than DELETE because it does not log each row individually.
  • DROP — deletes the object entirely: structure, data, indexes, everything.

DDL Usually Cannot Be Rolled Back

In most engines (MySQL and Oracle in particular) DDL statements perform an implicit commit: the moment you run one, any open transaction is committed and the change is permanent. A ROLLBACK afterwards will not save you. PostgreSQL is the notable exception — it supports transactional DDL.

This is why DROP TABLE on the wrong connection is one of the most feared mistakes in this profession. Press the DROP button here and note that the row counter goes to zero with no undo offered.

Constraints: Rules the Database Enforces

Constraints declared in DDL are checked on every write, forever, no matter which application is connecting:

  • PRIMARY KEY — unique and not null; identifies the row.
  • NOT NULL — the column must always have a value.
  • UNIQUE — no two rows may share this value.
  • FOREIGN KEY — the value must exist in the referenced table.
  • CHECK — an arbitrary condition, such as salary > 0.

Putting a rule here rather than in application code means it cannot be bypassed by a script, a migration or a careless intern with a database client.

The commands that define the shape of your data

SQL splits into families. DML moves data around — SELECT, INSERT, UPDATE, DELETE. DDL defines the containers that data lives in, and there are four commands worth knowing properly.

CREATE makes something: a table, an index, a view, a schema.

CREATE TABLE employees (
  id         SERIAL PRIMARY KEY,
  name       VARCHAR(100) NOT NULL,
  email      VARCHAR(255) UNIQUE,
  dept_id    INT REFERENCES departments(id),
  salary     DECIMAL(10,2) CHECK (salary > 0),
  hired_on   DATE NOT NULL DEFAULT CURRENT_DATE
);

ALTER changes it afterwards:

ALTER TABLE employees ADD COLUMN phone VARCHAR(20);
ALTER TABLE employees ALTER COLUMN name TYPE VARCHAR(150);
ALTER TABLE employees DROP COLUMN phone;
ALTER TABLE employees ADD CONSTRAINT salary_cap CHECK (salary < 1000000);

DROP removes the object and everything in it. TRUNCATE empties a table but keeps its structure.

DROP, DELETE and TRUNCATE are three different things

They get confused constantly, and the difference matters at exactly the moment you cannot undo it.

 What it removesSpeedRollbackTriggers fireResets identity
DELETE FROM tRows, one at a timeSlow on big tablesYesYesNo
TRUNCATE TABLE tAll rows, at onceVery fastIn PostgreSQL yes; MySQL noNoUsually yes
DROP TABLE tThe table itselfFastDepends on engineNoN/A

DELETE is the only one that can be given a WHERE clause. TRUNCATE deallocates the storage rather than removing rows individually, which is why it is orders of magnitude faster and why it cannot fire row-level triggers. DROP leaves nothing behind — no structure, no indexes, no permissions.

The critical operational point: in MySQL and Oracle, DDL causes an implicit commit. Any open transaction is committed before the DDL runs, and the DDL itself cannot be rolled back. In PostgreSQL and SQL Server, DDL is transactional — you can BEGIN, alter a table, decide against it, and ROLLBACK.

That difference changes how you write migrations. On PostgreSQL you can wrap a multi-step schema change in a transaction and get all-or-nothing. On MySQL you cannot, so each step has to be individually safe and reversible by hand.

Constraints: the rules the database enforces for you

Constraints are the reason a database is more than a file format. Each one is a rule the engine will not let any client break, including the buggy one you deploy at 5pm on a Friday.

  • PRIMARY KEY — unique and not null; the row's identity.
  • FOREIGN KEY — must match a row in another table, or be NULL. Add ON DELETE CASCADE to remove children automatically, or ON DELETE RESTRICT to refuse the parent's deletion.
  • UNIQUE — no duplicates. Allows multiple NULLs in most engines, since NULLs are not equal to each other.
  • NOT NULL — a value is required.
  • CHECK — an arbitrary condition, such as CHECK (end_date > start_date). Note it passes when the condition is UNKNOWN, so a NULL slips through unless you also declare NOT NULL.
  • DEFAULT — not strictly a constraint, but the same spirit: a value supplied when none is given.

Enforcing these in application code instead is the most common and most expensive schema mistake. There is always a second writer — a migration, a script, an admin console, a colleague's notebook — and it will not have your validation logic.

Declaring the shape, and letting the database enforce it

DDL defines what a table is, and every constraint you declare is a rule the database enforces for every writer forever -- including the ones written after you leave. This creates a table, then tries to break each rule in turn.

query.sqlSQLite
Result

Things to try

  1. Build a table and mark one column as PRIMARY KEY. Watch the generated CREATE TABLE update as you type.
  2. Press CREATE, then ALTER · ADD COLUMN. The new column appears on every existing row, filled with NULL — because the rows already existed and had no value to offer.
  3. Press TRUNCATE. Rows go to zero; the columns stay. The blueprint survives.
  4. Press DROP. Both structure and data vanish, and the log records the difference between the two operations.

In one line

DDL defines the contract your data must obey. Time spent choosing sensible types and constraints up front is repaid every day afterwards — and because these statements are usually irreversible, they deserve more care than any query you will write.

Changing a table that is in use

On a small table, ALTER TABLE is instant. On a large, busy one it can lock the table and take the application down, so the details matter.

  • Adding a nullable column is usually instant — metadata only.
  • Adding a column with a default historically rewrote every row. PostgreSQL 11+ and MySQL 8+ handle constant defaults without a rewrite; older versions do not.
  • Changing a column type generally rewrites the table and holds a strong lock.
  • Adding an index locks writes unless you use CREATE INDEX CONCURRENTLY (PostgreSQL) or an online index build.
  • Adding a NOT NULL constraint requires scanning the table to verify. Adding it as NOT VALID and validating later avoids the long lock in PostgreSQL.

The safe pattern for a risky change is the expand–migrate–contract sequence: add the new column, write to both old and new for a period, backfill in batches, switch readers over, then drop the old column in a later release. It takes three deployments instead of one, and it is how schema changes happen on systems that cannot go down.

Always set a short lock_timeout before running DDL on a live system. A migration that waits behind a long-running query will queue every other query behind itself, turning a slow migration into an outage.

Questions people ask

Can I roll back a DROP TABLE? In PostgreSQL, yes, if it was inside a transaction that you roll back. In MySQL, no. Either way, backups are the real answer.

What is the difference between SERIAL and IDENTITY? SERIAL is PostgreSQL's older shorthand that creates a sequence behind the scenes; GENERATED ALWAYS AS IDENTITY is the standard-compliant successor and is preferred in new schemas.

Should I use VARCHAR(255)? Only if 255 is a real limit. The number is an inherited habit from old MySQL row formats; in PostgreSQL there is no performance difference between VARCHAR(255) and TEXT.

Do constraints slow down writes? Slightly — each one is a check. Foreign keys also require an index lookup on the parent. The cost is small and the protection is large.

Can I add a foreign key to an existing table? Yes, and the engine validates every existing row first. On big tables use the NOT VALID then VALIDATE CONSTRAINT two-step where supported.

How do I version schema changes? With migration files in source control, applied in order and recorded in a table — Flyway, Liquibase, Alembic, or your framework's own tool. Manual DDL on production is how environments drift apart.

Recap in one screen

  • DDL defines structure: CREATE, ALTER, DROP, TRUNCATE.
  • DELETE removes rows and can be filtered; TRUNCATE empties fast; DROP removes the object entirely.
  • DDL is transactional in PostgreSQL and SQL Server, and auto-commits in MySQL and Oracle — this changes how migrations must be written.
  • Constraints are enforced by the engine against every client, which application-level validation can never be.
  • On live systems, prefer online index builds, short lock timeouts and the expand–migrate–contract pattern.

Predict, then reveal

About to run: Press CREATE, then ALTER · ADD COLUMN. Before it does — what happens to the readout?

Committing to an answer first is the point — the reveal runs the experiment on the visualisation above and reads the real value back, so nothing here is scripted.

Recall check

0 of 4

Say the answer out loud before you reveal it — recalling it is what makes it stick, and rereading it is not.

  1. What is meant by “Adding a column with a default” here?

  2. What is meant by “Changing a column type” here?

  3. What is meant by “Adding an index” here?

  4. What is meant by “Adding a NOT NULL constraint” here?

Cheat sheet

DDL in SQL

Data Definition Language builds the shape of your database. Design a table column by column, watch the CREATE TABLE statement write itself, then ALTER, TRUNCATE and DROP it to see what happens to the data each time.

DATABASE · vizlearn.in/database/ddl_in_sql.html

About the author

Ashish Jangra builds and maintains VizLearn. Every module here is written and the visualisation behind it hand-built, so the numbers in a readout come from the same code that draws the picture. Corrections are genuinely welcome and get priority over everything else — if a page states something wrong, or an animation misrepresents what the algorithm does, get in touch.