# Editing rows

Change cells, add or delete rows, read the exact SQL the app will run, then commit it in one transaction. Nothing reaches the server until you commit.

## Where to find it

| Action | How |
| --- | --- |
| Edit a cell | Double-click the cell |
| Add a row | `Row`, `⌘I` (`Ctrl+I`) |
| Duplicate rows | `Duplicate`, `⌘D` (`Ctrl+D`) |
| Delete rows | Select whole rows by their numbers, then `Delete` |
| Set NULL | Right-click, `Set NULL`, `⌘⇧N` (`Ctrl+Shift+N`) |
| Set DEFAULT | Right-click, `Set DEFAULT`, `⌘⇧D` (`Ctrl+Shift+D`) |
| Preview the SQL | `Preview`, `⌘⇧P` (`Ctrl+Shift+P`) |
| Commit | `Commit`, `⌘S` (`Ctrl+S`) |
`Discard`, `Preview` and `Commit` appear in a bar above the grid once a change is pending.

## Pending changes

Double-click a cell, type a new value and press Enter, or press `⌘I` (`Ctrl+I`) to add a row whose empty cells read `DEFAULT`. A changed cell is highlighted, a new row is tinted green, and a row marked for deletion is struck through in red. The bar above the grid counts them, for example `3 changes` and `1 edited · 1 new · 1 deleted`. Nothing is sent to the database yet.

[A customers city cell is double-clicked and changed to Porto, the cell turns highlighted, then Command I adds row 41 and its id and email are typed in.](https://bobbytables.app/docs/video/editing/01-edit-and-add-row.mp4)

_Edits collect in the grid until you commit._

![The customers grid with a highlighted Porto city cell, row 37 struck through in red and a new green row 41, under a bar reading 3 changes, 1 edited, 1 new, 1 deleted.](https://bobbytables.app/docs/img/editing/02-pending-changes.png)

_The pending bar counts edited, new and deleted rows._

## NULL and DEFAULT

`Set NULL` and `Set DEFAULT` in a cell's context menu write that value into the selected cells. The grid draws NULL as an italic `NULL` and a pending default as `DEFAULT`, so neither looks like an empty string. Both are pending changes like any other edit.

![The customers grid with a pending italic NULL in row 31's city cell, and the cell context menu open on row 32 showing Filter by value, Set NULL, Set DEFAULT, Quick Look, Row details and the copy actions.](https://bobbytables.app/docs/img/editing/03-set-null-menu.png)

_NULL is drawn in italics, never as an empty cell._

## Preview and commit

`Preview` opens `SQL preview` with the statements a commit will run, in order: deletes, then updates, then inserts. `Commit` runs them in one transaction. With the connection's safe mode on `Warn Writes`, the default, `Run these statements?` shows the complete SQL first and waits for `Run`. Its `Don't ask again` menu turns the prompt off `For this session` or always for the connection, as [Safe mode](https://bobbytables.app/docs/safe-mode) describes.

![The SQL preview dialog listing a DELETE for id 37, an UPDATE setting city to Porto for id 35, and an INSERT for id 41, with the note that 3 statements will run in one transaction.](https://bobbytables.app/docs/img/editing/04-sql-preview.png)

_The preview lists the statements in the order they run._

![The Run these statements? dialog for Bookshop (PostgreSQL) with three formatted statements, and the Don't ask again menu open on For this session and Always for Bookshop (PostgreSQL).](https://bobbytables.app/docs/img/editing/05-commit-confirmation.png)

_Don't ask again lasts for the session or is saved with the connection._

## When a commit fails

If the database rejects a statement, `Commit failed` opens with the database's message and the failing statement. Because the statements run in one transaction, nothing is committed and the changes stay pending. Choose `Back to table` to fix the value and commit again.

![The Commit failed dialog saying nothing was committed, with the duplicate key message for the reviews_book_id_customer_id_key constraint and the failing UPDATE statement.](https://bobbytables.app/docs/img/editing/06-commit-failed.png)

_The database's message and the failing statement appear together._

## Leaving with changes pending

Closing a tab with pending changes opens `Close tabs with unsaved changes?`. It lists the affected tabs and offers `Keep Editing`, `Discard` and `Commit Tables`. `Discard` in the pending bar asks before it throws away more than one change.

![The Close tabs with unsaved changes? dialog saying 3 pending table changes will be affected, listing the customers tab, with Keep Editing, Discard and Commit Tables.](https://bobbytables.app/docs/img/editing/08-close-tab-prompt.png)

_Commit Tables commits the pending edits before the tab closes._

## Good to know

- A table with no primary key opens read-only with the banner `This table has no primary key, so rows cannot be identified for editing.`
- A read-only connection disables every editing control.
- Redis, Cassandra and MongoDB stage changes in their own workspaces.
- The row inspector's JSON view adds to the same pending changes. See [Row inspector](https://bobbytables.app/docs/row-inspector).

![The notes table under an amber banner saying the table has no primary key, so rows cannot be identified for editing, with Row, Duplicate and Delete disabled.](https://bobbytables.app/docs/img/editing/07-no-primary-key.png)

_Without a primary key the grid stays read-only._

## Related

- [Table data](https://bobbytables.app/docs/table-data.md)
- [Row inspector](https://bobbytables.app/docs/row-inspector.md)
- [Safe mode and the console](https://bobbytables.app/docs/safe-mode.md)
- [Structure](https://bobbytables.app/docs/structure.md)
