> ## Documentation Index
> Fetch the complete documentation index at: https://ngquct-fix-license-sync-presentation.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Change Tracking

> Queue cell edits, row inserts and deletions, review the SQL, then save

export const what_0 = "Cell edits, inserts and deletes"

Nothing here reaches the server on its own. {what_0} queue on the tab, the toolbar counts them,
**Preview SQL** (`Cmd+Shift+P`) shows the statements they will produce, and `Cmd+S` runs them.

The toolbar counts what is pending, modified cells stay highlighted, `Cmd+Shift+P` shows the statements the queue will produce, and `Cmd+S` runs them. The queue belongs to the tab, so switching tabs leaves it alone.

<Frame caption="Data grid with pending changes highlighted">
  <img className="block dark:hidden" src="https://mintcdn.com/ngquct-fix-license-sync-presentation/jZwNgBkvtltEzZ4F/images/change-tracking.png?fit=max&auto=format&n=jZwNgBkvtltEzZ4F&q=85&s=3307e1a380e2f6ea8ee3e652e81f0b84" alt="Pending edits, inserts, and deletions highlighted in the data grid" width="1560" height="960" data-path="images/change-tracking.png" />

  <img className="hidden dark:block" src="https://mintcdn.com/ngquct-fix-license-sync-presentation/jZwNgBkvtltEzZ4F/images/change-tracking-dark.png?fit=max&auto=format&n=jZwNgBkvtltEzZ4F&q=85&s=ea2b9354746bcd45ea3649e97d44ede8" alt="Pending edits, inserts, and deletions highlighted in the data grid" width="1560" height="960" data-path="images/change-tracking-dark.png" />
</Frame>

## Editing a cell

Double-click a cell, or press `Enter` on it. `Enter` commits the edit to the queue, `Escape` cancels. Setting a value back to what it was drops it from the queue again. Some types open an editor of their own:

| Column type                         | Editor                                            |
| ----------------------------------- | ------------------------------------------------- |
| Date, time, datetime, timestamp     | Calendar and time picker, or edit as text         |
| Foreign key                         | Searchable list of referenced values              |
| Boolean, `BIT`, `TINYINT(1)`        | Checkbox, with a third state for nullable columns |
| `ENUM`                              | Searchable value list                             |
| `SET` (MySQL/MariaDB)               | Multi-select checkboxes                           |
| Array of a simple type (PostgreSQL) | Ordered list, one row per element                 |
| `JSON`, `JSONB`, `BLOB`, binary     | [Cell viewers](/features/json-viewer)             |

<Frame caption="Type-specific cell editor">
  <img className="block dark:hidden" src="https://mintcdn.com/ngquct-fix-license-sync-presentation/jZwNgBkvtltEzZ4F/images/date-picker-editor.png?fit=max&auto=format&n=jZwNgBkvtltEzZ4F&q=85&s=aeef26db4459db60064e338ce36d6490" alt="Cell editor" width="1560" height="960" data-path="images/date-picker-editor.png" />

  <img className="hidden dark:block" src="https://mintcdn.com/ngquct-fix-license-sync-presentation/jZwNgBkvtltEzZ4F/images/date-picker-editor-dark.png?fit=max&auto=format&n=jZwNgBkvtltEzZ4F&q=85&s=7bc75cfe9ac3f1a2d3b686736ed25cb9" alt="Cell editor" width="1560" height="960" data-path="images/date-picker-editor-dark.png" />
</Frame>

Right-click an editable cell and open **Set Value** for the common ones without typing: **Empty**, **NULL** on a nullable column, **Default** on a column that has one, and date functions such as `NOW()` or `CURRENT_DATE` on date columns.

## Adding and deleting rows

* **Add Row** (`Cmd+Shift+N`), the **+** button, or **Edit > Add Row**. The row appears at the bottom, columns with a default pre-filled as `DEFAULT`. Later edits to it fold into the INSERT rather than queueing as updates.
* **Duplicate Row** (`Cmd+Shift+D`) on the right-click menu copies a row and resets its primary key to `DEFAULT`, so the database assigns a new one.
* **Delete**: select rows by their row numbers (`Shift`-click for a range, `Cmd`-click for separate rows) and press `Delete`. They stay visible with a strikethrough, and saving asks "Delete 5 rows?" before they go.
* **Paste** on the right-click menu inserts copied rows as new rows.
* **Fill Column** on the header right-click menu writes one value into every loaded row, skipping primary key columns.

## When the grid will not edit

A tab opened from the sidebar edits its table directly. A query tab edits only when the app can prove the rows came from exactly one table:

| Query                                                                                       | Editable          |
| ------------------------------------------------------------------------------------------- | ----------------- |
| `SELECT * FROM orders o WHERE o.id = 1`                                                     | Yes, alias or not |
| Comments, `DISTINCT`, `ORDER BY`, `LIMIT`, `FOR UPDATE`                                     | Yes               |
| `SELECT * FROM public.orders` on the schema you are browsing                                | Yes               |
| The same query naming any other schema                                                      | No                |
| Joins, comma joins, subqueries in `FROM`, CTEs, `UNION`, `EXCEPT`, `INTERSECT`, `FROM ONLY` | No                |

To change rows a join returned, open one of its tables from the sidebar and edit there. To edit through another schema, switch the session to that schema first.

Two more shapes look editable and refuse. A column renamed with `AS` cannot be written back, though the rest of the row still can. A query that renames or omits the primary key blocks the save outright, because nothing is left to identify the row by.

Individual columns stay read-only where the server owns them: generated columns, which are computed on write and left out of every INSERT and UPDATE, SQL export included, and columns the driver marks immutable, such as MongoDB's `_id`. A connection set to the Read-Only [safe mode](/features/safe-mode) level edits nothing at all.

## Saving

Press `Cmd+S`, or click the toolbar checkmark. Values go out as bound parameters; `DEFAULT` and SQL functions such as `NOW()` are written into the statement as they stand.

| Change        | Generated SQL                           |
| ------------- | --------------------------------------- |
| Cell edit     | `UPDATE … SET column = ? WHERE pk = ?`  |
| Row insertion | `INSERT INTO … (columns) VALUES (?, …)` |
| Row deletion  | `DELETE FROM … WHERE pk = ? OR pk = ?`  |

A table without a primary key is matched on every original column value instead, with `IS NULL` for the nulls.

On an engine with transactions, the statements run inside one, so a failure rolls the whole save back and the table is left as it was. Without them, the statements that ran before the failure stand. Either way a failed save reports **Save Failed** with the server's message and keeps the queue intact, so correct the value and save again. A save that succeeds clears the queue, clears undo, and reloads the grid.

There is no discard button. Undo the edits, or take the **Discard Unsaved Changes?** prompt that appears when you refresh, sort, filter, change page, or close the tab with edits pending.

## Previewing the SQL

`Cmd+Shift+P`, or the eye button in the toolbar, lists the statements with their parameter values inlined, so the preview reads as what will run. **Copy All** copies every statement.

## Undo and redo

`Cmd+Z` and `Cmd+Shift+Z`. Focus decides what they act on: text in the SQL editor, queued changes in the grid. Deleting several rows undoes as one step. The stacks are per tab, and a save clears them.

## Structure changes

Column, index, foreign key, and primary key edits queue in the same place and go out with the same Save, previewed as DDL instead of DML. See [Table Structure](/features/table-structure).
