Queries and CRUD

DataTier 1 · hear it this weekPhase 2 · Make it a store

Everything any app does to data is one of four things: create, read, update, delete. A query is a request to the database to do one of them.

Storing data is only useful if you can ask precise questions of it and change it safely: find every unpaid order from today, mark this one shipped. Scanning everything by hand in code would be slow and error-prone. Queries and CRUD exist as the standard read, create, update, and delete operations, so the database does the finding and changing efficiently and the same way every time.

CRUD is the whole vocabulary of data. Placing an order creates a row. Viewing your orders reads rows. Changing your address updates a row. Removing a saved card deletes one. Every feature decomposes into these.

A query is the instruction that performs one: "read all orders for customer 88231," "update stock of product 1042 to 12." The backend sends queries to the database constantly.

A junior PM, stuck

In the delete-account discussion the dev asked me "hard delete or soft delete?" and I said soft, because it sounded safer, without actually knowing what each one does to the data. Now I am worried I picked based on the nicer-sounding word. I want to see what the row looks like after each before I commit us to one.

Everything an app does to data is one of four moves: create, read, update, delete. Delete is the only one of the four that cannot be taken back, which is exactly why your question matters. Below is one customer's checkout session as the database saw it, real rows, the four queries in order, and the two kinds of delete side by side so you can see which one keeps the row and which one is gone for good.

One order's life in the orders table: create, read, update, delete
orders table, before this checkout
id | customer | product | amount | status | deleted_at
o_5510 | u_88231 | p_1045 | 240 | shipped | null
o_5511 | u_88231 | p_1050 | 120 | shipped | null
Create, read, update: three queries from the session
INSERT INTO orders (id, customer, product, amount, status)
VALUES ('o_5512', 'u_88231', 'p_1042', 649, 'placed');
INSERT 0 1
SELECT id, product, amount, status FROM orders WHERE customer = 'u_88231';
o_5510 | p_1045 | 240 | shipped
o_5511 | p_1050 | 120 | shipped
o_5512 | p_1042 | 649 | placed
(3 rows)
UPDATE orders SET status = 'shipped' WHERE id = 'o_5512';
UPDATE 1
Delete: soft versus hard, on the same row
UPDATE orders SET deleted_at = '2026-03-06T13:20:00Z' WHERE id = 'o_5512';
SELECT id, status, deleted_at FROM orders WHERE id = 'o_5512';
o_5512 | shipped | 2026-03-06T13:20:00Z
(1 row)
DELETE FROM orders WHERE id = 'o_5512';
DELETE 1
SELECT id, status FROM orders WHERE id = 'o_5512';
(0 rows)

Click a step to see the lines it points at.

Choosing soft or hard delete on which word sounds safer. Soft delete keeps personal data you may be legally required to erase; hard delete destroys history support might need. It is a real trade-off, not a vibe.
Forgetting that a soft-deleted row is still in the table. If the app does not filter on deleted_at, a soft-deleted order reappears in lists and reports; the hiding is your job to spec, not automatic.
Speccing only the happy CRUD paths. For any object, walk all four moves: create, read, update, delete. The one you forget, usually delete or edit, becomes the gap a user or auditor finds later.
Treating a read as risky and a delete as routine. A SELECT changes nothing and can be run freely; a DELETE with a wrong or missing WHERE can wipe rows you never meant to touch, so ask for the row count on any write.
Promising deletion without checking soft versus hard underneath. If "delete my account" only sets a flag, the data still exists; when a user invokes the right to be forgotten, confirm which delete actually runs.

Reply in the thread: "Soft delete: we set a deleted_at flag and hide the row, so support keeps the history and we can still hard-delete on a real erasure request. Let me confirm the app filters out flagged rows everywhere." You read what each of the four CRUD moves does to a single row, which is the skill.

Thinking in CRUD helps you spec features: for any object, ask what happens on create, read, update, and delete. Missing one is a common gap.
"Soft delete" (mark as deleted but keep the row) versus real delete is a product decision with legal and analytics consequences.

"Do we hard-delete the account or just flag it? Support may need the history."

Appears in Phase 2, Make it a store.