Skip to content

📘 03-02: DML — Insert, Update, Delete

SQL & Databases

Module 03: SQL Fundamentals

Home All Notes Practice Quiz

💡 Three Ways to Change Data

Once tables exist (see DDL), DML gives you three operations to change what's in them:

Statement Effect
INSERT Adds new row(s)
UPDATE Modifies existing row(s)
DELETE Removes existing row(s)

We'll use the Wedgewood Pacific employee and assignment tables from the previous note.


📌 INSERT

INSERT INTO employee (first_name, last_name, department_name, position, supervisor, email_address)
VALUES ('Mary', 'Jacobs', 'Administration', 'CEO', NULL, 'Mary.Jacobs@WP.com');

INSERT INTO employee (first_name, last_name, department_name, position, supervisor, email_address)
VALUES ('Rosalie', 'Jackson', 'Administration', 'Admin Assistant', 1, 'Rosalie.Jackson@WP.com');

The column list after the table name tells SQL which columns you're supplying values for, and in what order — the order of columns in the INSERT doesn't have to match the table's physical column order, as long as it matches the order of the values you provide.

-- Column order doesn't matter, as long as VALUES matches it
INSERT INTO employee (email_address, last_name, first_name, department_name)
VALUES ('Ken.Evans@WP.com', 'Evans', 'Ken', 'Finance');

You can omit the column list entirely, but then you must supply a value (or DEFAULT) for every column in table order — fragile if the schema changes later, so naming columns explicitly is the safer habit.

Multi-row insert — one statement, several rows:

INSERT INTO assignment (project_id, employee_number, hours_worked) VALUES
    (1000, 1,  30.00),
    (1000, 6,  50.00),
    (1000, 10, 50.00),
    (1000, 16, 75.00);

📌 UPDATE

UPDATE always needs a WHERE clause unless you genuinely intend to change every row in the table:

-- Give everyone in Sales and Marketing a title bump
UPDATE employee
SET position = 'Senior ' || position
WHERE department_name = 'Sales and Marketing';

-- Reassign an employee to a new supervisor
UPDATE employee
SET supervisor = 12
WHERE employee_number = 13;

-- Update multiple columns at once
UPDATE assignment
SET hours_worked = 80.00
WHERE project_id = 1000 AND employee_number = 17;

Tip

Before running an UPDATE (or DELETE) against real data, run the same WHERE clause as a SELECT first: SELECT * FROM employee WHERE department_name = 'Sales and Marketing';. If that returns the rows you expect, the UPDATE/DELETE will touch exactly those rows and no others.


📌 DELETE

-- Remove one specific assignment
DELETE FROM assignment
WHERE project_id = 1600 AND employee_number = 7;

-- Remove every assignment for a finished project
DELETE FROM assignment
WHERE project_id = 1000;

Note

DELETE FROM assignment; with no WHERE clause deletes every row in the table — a fully valid, syntactically correct statement that has ended more than one career-defining incident. Postgres will not ask you to confirm. Always check your WHERE clause with a SELECT first.


📌 UPSERT — Insert, or Update if It Already Exists

A common need: "insert this row, but if a row with this key already exists, update it instead." Every major database has its own syntax for this — full mastery of MERGE is Module 08 material, but here's the shape of each so you recognize it:

PostgreSQL — INSERT ... ON CONFLICT:

INSERT INTO assignment (project_id, employee_number, hours_worked)
VALUES (1000, 1, 35.00)
ON CONFLICT (project_id, employee_number)
DO UPDATE SET hours_worked = EXCLUDED.hours_worked;

EXCLUDED refers to the row that would have been inserted — here, it means "overwrite hours_worked with the new value I tried to insert."

Note

Same idea, different syntax across databases.

Database Upsert syntax
PostgreSQL INSERT ... ON CONFLICT (key) DO UPDATE SET ...
MySQL INSERT ... ON DUPLICATE KEY UPDATE ...
SQL Server MERGE INTO target USING source ON ... WHEN MATCHED THEN UPDATE ... WHEN NOT MATCHED THEN INSERT ...
SQLite INSERT ... ON CONFLICT (key) DO UPDATE SET ... (same as Postgres)

SQL Server's MERGE is the most general of these — it can also handle WHEN NOT MATCHED BY SOURCE THEN DELETE in one statement. Postgres and MySQL support a MERGE statement too as of recent versions, but the ON CONFLICT / ON DUPLICATE KEY shorthand remains the idiomatic choice for simple upserts. We'll write full MERGE statements in Module 08.


📌 RETURNING — See What You Just Changed

PostgreSQL lets any DML statement report back the rows it affected, without a separate SELECT:

INSERT INTO employee (first_name, last_name, department_name, email_address)
VALUES ('Grace', 'Lin', 'InfoSystems', 'Grace.Lin@WP.com')
RETURNING employee_number;

UPDATE assignment
SET hours_worked = hours_worked + 5
WHERE project_id = 1100 AND employee_number = 1
RETURNING *;

RETURNING is especially handy for grabbing a newly generated SERIAL primary key immediately after an INSERT, without a round trip to look it up.


See also: DDL: Tables & Data Types, SELECT: Filtering & Sorting