> **Can't find what you're looking for?** Use `search_docs` on the docs MCP server at `https://docs.ampdb.io/api/mcp` to find what you need.

# ampctl table

Status: In development.

`ampctl table` manages [table revisions](/managing-amp/table-revisions). A revision is a directory in Amp's
[storage](/running-amp/storage) that holds one table's Parquet files, like the `blocks` table of
`acme/eth_mainnet@1.0.0`. A table can have several revisions, but queries read only one of them, its active revision.
These commands list revisions and their files, switch which one is active, add revisions from directories you copied
into storage, and delete revisions and their files. To learn when you'd do that, like to serve data you imported or to
recover after losing the metadata database, see [Table Revisions](/managing-amp/table-revisions).

Some of these commands can't be undone. [What each command changes](/clis/ampctl/table#what-each-command-changes) says which.

## Prerequisites

* A running Amp, like the one the [Quickstart](/get-started/quickstart) starts with
  [solo mode](/running-amp/solo-mode), with its `acme/eth_mainnet@1.0.0` dataset deployed, and
  [`acme/eth_transfers@1.0.0`](/datasets/derived-datasets#the-erc-20-transfers-dataset), a derived dataset you
  create on top of it.
* `ampctl`, [installed](/clis/ampctl#install) and [connected to it](/clis/ampctl#connect-to-amp).

Every command also takes the [global flags](/clis/ampctl#global-flags): `--admin-url`, `--auth-token`, and `--json`,
which prints the result as [JSON](/clis/ampctl#json-output).

## Revisions

Deploying a dataset creates a revision for each of its tables and activates it, and the dataset's job writes the
table's files there. Each revision has:

* **A location ID**: the number Amp gives the revision when it creates or registers it, like `1`. Most commands take
  it. IDs only grow and are never reused, but they can skip numbers.
* **A path**: its directory, relative to Amp's data directory. In solo mode, that's `.amp/data` in the directory you
  started `ampd solo` from; otherwise, it's the directory or bucket your [storage](/running-amp/storage) is set to. Amp
  names the directories it creates `namespace/name/table/ID`, like
  `acme/eth_mainnet/blocks/01a18eaa-a142-7172-a120-0b839837fc79`.
* **A table**: the dataset and table it belongs to. Amp records the dataset version by its
  [manifest hash](/get-started/glossary), so a revision belongs to that manifest whichever version tags point to it.
* **Whether it's active**: queries read a table's active revision only, and a table has at most one.
* **A writer**: the job that writes to it, like the dataset's materialization job, if any. `prune`, `delete`, and
  `truncate` refuse to change a revision while its writer runs.

`activate`, `deactivate`, and `register` name a table by its dataset, as `namespace/name@version`, and its name. The
version can also be `latest` or a manifest hash, like `acme/eth_mainnet@latest`. Without a version, the command fails:

```
✗ failed to activate table revision
  → unexpected response (status 422): Failed to deserialize the JSON body into the target type: dataset: invalid reference format 'acme/eth_mainnet', missing '@' separator for revision at line 1 column 52
```

## What each command changes

| Command                                                                                          | What it changes                                                                                                  | How to undo it                                                       |
| ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| [`list`](/clis/ampctl/table#ampctl-table-list), [`get`](/clis/ampctl/table#ampctl-table-get), [`histogram`](/clis/ampctl/table#ampctl-table-histogram) | Nothing.                                                                                                         | Nothing to undo.                                                     |
| [`register`](/clis/ampctl/table#ampctl-table-register)                                                             | Adds a revision. Nothing in storage changes.                                                                     | Delete the revision.                                                 |
| [`restore`](/clis/ampctl/table#ampctl-table-restore)                                                               | Records the files in a revision's directory. If the revision is active, queries read them at once.               | Delete the revision, if it's inactive.                               |
| [`activate`](/clis/ampctl/table#ampctl-table-activate)                                                             | Which revision of a table queries read.                                                                          | Activate the revision that was active before.                        |
| [`deactivate`](/clis/ampctl/table#ampctl-table-deactivate)                                                         | Leaves a table with no active revision, so queries of it fail.                                                   | Activate a revision.                                                 |
| [`prune`](/clis/ampctl/table#ampctl-table-prune)                                                                   | Takes the files outside a revision's canonical chain out of it, and has them deleted from storage after a delay. | **Can't be undone.**                                                 |
| [`delete`](/clis/ampctl/table#ampctl-table-delete)                                                                 | Deletes an inactive revision and its record of its files. The files stay in storage.                             | Register and restore its directory again. It gets a new location ID. |
| [`truncate`](/clis/ampctl/table#ampctl-table-truncate)                                                             | Deletes an inactive revision's files from storage, then the revision.                                            | **Can't be undone.**                                                 |

Queries never read an inactive revision, so deleting or truncating one doesn't change what they return. What you lose
is the revision, and with `truncate`, its data.

## `ampctl table list`

Lists table revisions, newest first, with their tables and whether they're active.

```
ampctl table list [OPTIONS]
```

| Flag                      | Type              | Default | Description                                                                                  |
| ------------------------- | ----------------- | ------- | -------------------------------------------------------------------------------------------- |
| `-a`, `--active <ACTIVE>` | `true` or `false` | both    | Lists only active revisions (`true`) or only inactive ones (`false`), like `--active false`. |
| `-l`, `--limit <LIMIT>`   | integer           | `100`   | The most revisions to list, like `--limit 10`.                                               |
| `--last-id <LAST_ID>`     | integer           | none    | Lists only revisions with a lower location ID, to get the next page, like `--last-id 3`.     |

Its alias is `ampctl table ls`, and `ampctl tables` is the same as `ampctl table`.

:::terminal
```bash
ampctl table list
```

```
Revisions (4):
  4 - acme/eth_transfers transfers [active]
  3 - acme/eth_mainnet transactions [active]
  2 - acme/eth_mainnet logs [active]
  1 - acme/eth_mainnet blocks [active]
```
:::

Each line has a revision's location ID, its dataset and table, and whether it's active. The line doesn't say which
version of the dataset the revision belongs to: [`get`](/clis/ampctl/table#ampctl-table-get) shows its manifest hash.

`list` prints at most 100 revisions unless you pass `--limit`. To page through them, pass the last location ID a page
printed as `--last-id`:

:::terminal
```bash
ampctl table list --limit 2
```

```
Revisions (2):
  4 - acme/eth_transfers transfers [active]
  3 - acme/eth_mainnet transactions [active]
```
:::

:::terminal
```bash
ampctl table list --limit 2 --last-id 3
```

```
Revisions (2):
  2 - acme/eth_mainnet logs [active]
  1 - acme/eth_mainnet blocks [active]
```
:::

When no revision matches, `list` prints `No revisions found`, or `{"revisions":[]}` with `--json`, and exits with
code 0. With `--json`, each revision has the fields [`get`](/clis/ampctl/table#ampctl-table-get) prints.

`list` can't filter by dataset or table, so use `jq` to list one table's revisions. Go through every page, since a page
holds 100 revisions by default and the table's older revisions can be past it. This loop passes each page's last
location ID to `--last-id`, and stops at the first page with no revisions:

:::terminal
```bash
last_id=
while
  page=$(ampctl table list ${last_id:+--last-id=$last_id} --json)
  last_id=$(jq '.revisions[-1].id // empty' <<< "$page")
  [ -n "$last_id" ]
do
  jq -r '
    .revisions[]
    | select(
        .metadata.dataset_namespace == "acme"
        and .metadata.dataset_name == "eth_mainnet"
        and .metadata.table_name == "blocks"
      )
    | "\(.id) \(.active) \(.path)"
  ' <<< "$page"
done
```

```
1 true acme/eth_mainnet/blocks/01a18eaa-a142-7172-a120-0b839837fc79
```
:::

## `ampctl table get`

Shows a revision: its path, whether it's active, its writer, and the dataset and table it belongs to.

```
ampctl table get [OPTIONS] LOCATION_ID
```

| Argument      | Type    | Default  | Description                                                                      |
| ------------- | ------- | -------- | -------------------------------------------------------------------------------- |
| `LOCATION_ID` | integer | required | The revision's location ID, as [`list`](/clis/ampctl/table#ampctl-table-list) prints it, like `1`. |

:::terminal
```bash
ampctl table get 1
```

```
→ Revision 1
  Path:      acme/eth_mainnet/blocks/01a18eaa-a142-7172-a120-0b839837fc79
  Active:    true
  Writer:    2
  Dataset:   acme/eth_mainnet
  Manifest:  b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b
  Table:     blocks
```
:::

| Field      | JSON field                                            | Description                                                                                                                                                |
| ---------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Path`     | `path`                                                | The revision's directory, relative to Amp's data directory.                                                                                                |
| `Active`   | `active`                                              | Whether queries of the table read this revision.                                                                                                           |
| `Writer`   | `writer`                                              | The ID of the job that writes to it. See it with [`ampctl job inspect`](/clis/ampctl/job). Left out when there's none, like for a revision you registered. |
| `Dataset`  | `metadata.dataset_namespace`, `metadata.dataset_name` | The dataset it belongs to.                                                                                                                                 |
| `Manifest` | `metadata.manifest_hash`                              | The manifest hash of the dataset version it belongs to.                                                                                                    |
| `Table`    | `metadata.table_name`                                 | The table it belongs to.                                                                                                                                   |

With `--json`:

:::terminal
```bash
ampctl table get 1 --json
```

```json
{
  "id": 1,
  "path": "acme/eth_mainnet/blocks/01a18eaa-a142-7172-a120-0b839837fc79",
  "active": true,
  "writer": 2,
  "metadata": {
    "dataset_namespace": "acme",
    "dataset_name": "eth_mainnet",
    "manifest_hash": "b9e2ebd92c0752ba8a61a233f9cc5d3f4f8b601b1b789a882a5dd8ece9bca56b",
    "table_name": "blocks"
  }
}
```
:::

A location ID that doesn't exist fails with exit code 1.

Every command that takes a location ID needs a number. Anything else fails before anything is sent.

## `ampctl table histogram`

Shows how many files a revision has and how their sizes are spread out. A table split into many small files is slower
to query; [compaction](/running-amp/storage/compaction) merges them.

```
ampctl table histogram [OPTIONS] LOCATION_ID
```

| Argument      | Type    | Default  | Description                           |
| ------------- | ------- | -------- | ------------------------------------- |
| `LOCATION_ID` | integer | required | The revision's location ID, like `2`. |

:::terminal
```bash
ampctl table histogram 2
```

```
→ Histogram for location 2
  Files:     1
  Total:     2.15 MiB
  Min size:  2.15 MiB
  Max size:  2.15 MiB
  Avg size:  2.15 MiB

  RANGE                FILES    TOTAL SIZE
  1 MB - 200 MB        1        2.15 MiB
```
:::

Below the totals, each line is a range of file sizes that has files in it, with how many and their total size. The
ranges are below 1 KB, then 200 KB wide up to 1 MB, 200 MB wide up to 1 GB, 1 GB wide up to 10 GB, and above 10 GB.
Their labels count 1 KB as 1,024 bytes.

With `--json`, sizes are in bytes, and each bucket's `range` is its lowest size and the size it stays under:

:::terminal
```bash
ampctl table histogram 2 --json
```

```json
{
  "location_id": 2,
  "file_count": 1,
  "total_size": 2249906,
  "min_size": 2249906,
  "max_size": 2249906,
  "avg_size": 2249906,
  "buckets": [{ "range": [1048576, 209715200], "file_count": 1, "total_size": 2249906 }]
}
```
:::

Only the files in the revision count: not the files [`prune`](/clis/ampctl/table#ampctl-table-prune) or compaction scheduled for
deletion, nor files in its directory that [`restore`](/clis/ampctl/table#ampctl-table-restore) hasn't recorded. A revision with no files
fails with exit code 1, and so does a location ID that doesn't exist. To tell them apart, run
[`get`](/clis/ampctl/table#ampctl-table-get).

```
✗ no files found for location '7'
```

## `ampctl table register`

Adds a revision for a table from a directory in storage, without reading its files or activating it. Use it to bring
in files Amp didn't write there itself, like a copy from another Amp's storage, or a backup.

```
ampctl table register [OPTIONS] DATASET TABLE_NAME PATH
```

| Argument     | Type   | Default  | Description                                                                                          |
| ------------ | ------ | -------- | ---------------------------------------------------------------------------------------------------- |
| `DATASET`    | string | required | The dataset the revision belongs to, as `namespace/name@version`, like `acme/eth_mainnet@1.0.0`.     |
| `TABLE_NAME` | string | required | The table the revision belongs to, like `blocks`.                                                    |
| `PATH`       | string | required | The revision's directory, relative to Amp's data directory, like `acme/eth_mainnet/blocks/imported`. |

To try it, copy the `blocks` table's revision to a new directory. Run this from the directory you started `ampd solo`
from:

```bash
cp -R ".amp/data/$(ampctl table get 1 --json | jq -r .path)" .amp/data/acme/eth_mainnet/blocks/imported
```

Then register the copy:

:::terminal
```bash
ampctl table register acme/eth_mainnet@1.0.0 blocks acme/eth_mainnet/blocks/imported
```

```
✓ Revision registered for table blocks in dataset acme/eth_mainnet@1.0.0 (location_id: 5)
```
:::

The new revision is inactive and has no files yet: run [`restore`](/clis/ampctl/table#ampctl-table-restore) to record them, then
[`activate`](/clis/ampctl/table#ampctl-table-activate) to have queries read them. With `--json`:

```json
{
  "location_id": 5,
  "dataset": "acme/eth_mainnet@1.0.0",
  "table_name": "blocks",
  "path": "acme/eth_mainnet/blocks/imported"
}
```

`register` checks only that the dataset version exists. It doesn't check that the directory exists or holds files, or
that the table is in the dataset's manifest. Leading and trailing slashes in `PATH` are dropped.

A path that's already registered isn't registered again: `register` prints the existing revision's location ID. That
revision keeps the dataset and table it was registered with, even when the message names others, so check it with
[`get`](/clis/ampctl/table#ampctl-table-get).

A path that's empty or has an empty part fails:

```
✗ failed to register table revision
  → failed to register table revision
    → REGISTER_TABLE_REVISION_ERROR: Failed to register table revision: Invalid revision path: invalid table revision path: Path "a//b" contained empty path segment
```

A dataset version that doesn't exist fails with `✗ dataset not found: acme/eth_mainnet@2.0.0`.

## `ampctl table restore`

Reads the Parquet files in a revision's directory and records them, so that queries can read them once the revision is
active. Run it after [`register`](/clis/ampctl/table#ampctl-table-register), and after adding files to a revision's directory.

```
ampctl table restore [OPTIONS] LOCATION_ID
```

| Argument      | Type    | Default  | Description                           |
| ------------- | ------- | -------- | ------------------------------------- |
| `LOCATION_ID` | integer | required | The revision's location ID, like `5`. |

:::terminal
```bash
ampctl table restore 5
```

```
✓ Revision 5 restored (1 files)
```
:::

The count is every file in the directory, including those already recorded. Running `restore` again is safe: it skips
the files it already recorded. With `--json`, it prints `{"location_id":5,"total_files":1}`.

Every file in the directory must be a Parquet file that Amp wrote, since `restore` reads the block range Amp records
in each one. Any other file, whatever its extension, stops the restore, and the files recorded before it stay
recorded:

```
✗ failed to restore table revision
  → failed to register revision files
    → REGISTER_FILES_ERROR: Failed to register files for revision: Failed to read Amp segment metadata from file: Amp metadata missing for file: acme/eth_mainnet/blocks/imported/export.parquet
```

`restore` doesn't notice a file you replaced with another of the same name: it keeps what it recorded about the old
one, and queries of it then fail with errors like `snappy: corrupt input`. To pick up replaced files,
[delete](/clis/ampctl/table#ampctl-table-delete) the revision, then register and restore its directory again.

A location ID that doesn't exist fails with `✗ revision with location ID '7' not found`.

## `ampctl table activate`

Makes a revision the one queries read for its table, in place of the revision that was active. The switch happens at
once: a query reads either the old revision or the new one. No files are copied.

```
ampctl table activate [OPTIONS] DATASET TABLE_NAME LOCATION_ID
```

| Argument      | Type    | Default  | Description                                                                      |
| ------------- | ------- | -------- | -------------------------------------------------------------------------------- |
| `DATASET`     | string  | required | The table's dataset, as `namespace/name@version`, like `acme/eth_mainnet@1.0.0`. |
| `TABLE_NAME`  | string  | required | The table, like `blocks`.                                                        |
| `LOCATION_ID` | integer | required | The revision to activate, like `5`.                                              |

```bash
ampctl table activate acme/eth_mainnet@1.0.0 blocks 5
```

Queries of `acme/eth_mainnet@1.0.0`'s `blocks` table now read the copy, and the revision that was active stays,
inactive:

:::terminal
```bash
ampctl table list
```

```
Revisions (5):
  5 - acme/eth_mainnet blocks [active]
  4 - acme/eth_transfers transfers [active]
  3 - acme/eth_mainnet transactions [active]
  2 - acme/eth_mainnet logs [active]
  1 - acme/eth_mainnet blocks [inactive]
```
:::

To switch back, activate the previous revision: `ampctl table activate acme/eth_mainnet@1.0.0 blocks 1`. With
`--json`, `activate` prints `{"dataset":"acme/eth_mainnet@1.0.0","table_name":"blocks","location_id":1}`.

:::warning
`activate` doesn't check the revision you give it. It activates a revision of another table, like the `logs` revision
`2` for `blocks`, and queries of the table then fail with errors like
`Non-nullable column 'hash' is missing from the physical schema`. It also activates a revision with no recorded files,
and queries then fail with `no common canonical watermark is available for batch snapshot`. Check the revision's
table with [`get`](/clis/ampctl/table#ampctl-table-get), and [`restore`](/clis/ampctl/table#ampctl-table-restore) it before you activate it.
:::

### Errors

* `✗ table 'receipts' not found in manifest for dataset 'acme/eth_mainnet@1.0.0'`: the dataset has no table by that
  name. Check its tables with [`ampctl dataset inspect`](/clis/ampctl/dataset#ampctl-dataset-inspect).

* `✗ table 'blocks' not registered for dataset 'acme/eth_mainnet@1.1.0'`: that dataset version was never deployed, so
  its tables don't exist yet. Activate the revision with
  [`ampctl dataset restore`](/clis/ampctl/dataset#ampctl-dataset-restore) instead, which creates the table:
  `ampctl dataset restore acme/eth_mainnet@1.1.0 --table blocks --location-id 5`.

* `✗ dataset not found: acme/eth_mainnet@2.0.0`: the dataset or version doesn't exist.

* A location ID that doesn't exist fails with a database error:

  ```
  ✗ failed to activate table revision
    → failed to activate table revision
      → ACTIVATE_TABLE_REVISION_ERROR: Failed to activate table revision: Failed to mark table revision as active: Error executing database query: error returned from database: insert or update on table "physical_tables" violates foreign key constraint "physical_tables_active_revision_id_fkey" at line 2539: …
  ```

* `error: unexpected argument '--location-id' found`: the location ID is an argument, not a flag, despite the
  examples in `ampctl table activate --help`. Drop `--location-id`.

## `ampctl table deactivate`

Leaves a table with no active revision, so queries of it fail until you activate one. Its revisions and files stay as
they are.

```
ampctl table deactivate [OPTIONS] DATASET TABLE_NAME
```

| Argument     | Type   | Default  | Description                                                                      |
| ------------ | ------ | -------- | -------------------------------------------------------------------------------- |
| `DATASET`    | string | required | The table's dataset, as `namespace/name@version`, like `acme/eth_mainnet@1.0.0`. |
| `TABLE_NAME` | string | required | The table, like `blocks`.                                                        |

```bash
ampctl table deactivate acme/eth_mainnet@1.0.0 blocks
```

Queries of the table then fail:

:::terminal
```bash
ampsql 'SELECT count(*) AS blocks FROM "acme/eth_mainnet@1.0.0".blocks'
```

```
✗ query failed
  → gRPC status error
    → code: 'Internal error', message: "failed to pin plan source-table revisions | Caused by: table 'acme/eth_mainnet@1.0.0.blocks' has no synced data"
```
:::

Deactivating a raw dataset's `blocks` table also stops queries of its other tables, and of the datasets derived from
it, like `acme/eth_transfers@1.0.0`, which fail with `failed to resolve batch query snapshot`. Deactivating any other
table affects only that table.

`deactivate` succeeds when the table has no active revision already. With `--json`, it prints
`{"dataset":"acme/eth_mainnet@1.0.0","table_name":"blocks"}`. A table that isn't in the dataset, or whose dataset
version was never deployed, fails:

```
✗ table 'receipts' not found for dataset 'acme/eth_mainnet@1.0.0'
```

## `ampctl table prune`

Takes the files outside a revision's canonical chain out of the revision, and schedules them for
[garbage collection](/running-amp/storage/garbage-collection), which deletes them from storage. Each of a table's
files, or segments, covers a range of blocks, and the canonical chain is the run of adjacent segments that queries
read. Segments outside it, like the ones a [reorg](/get-started/concepts/reorgs) replaced, take up storage without
being queried.

```
ampctl table prune [OPTIONS] LOCATION_ID
```

| Argument / flag                 | Type    | Default  | Description                                                                                                                                      |
| ------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `LOCATION_ID`                   | integer | required | The revision's location ID, like `1`. It can be active.                                                                                          |
| `--before-block <BEFORE_BLOCK>` | integer | none     | Prunes only segments that end before this block, like `--before-block 24000050`, and keeps recent ones.                                          |
| `--gc-delay <GC_DELAY>`         | integer | `3600`   | How many seconds to wait before the files can be deleted from storage, like `--gc-delay 7200`. Queries already running can read them until then. |
| `-f`, `--force`                 | flag    | off      | Prunes without asking first. Use it in scripts.                                                                                                  |

Without `--force`, `prune` asks first. Any answer but `y` or `yes` prunes nothing and exits with code 0, and so does
a script without `--force`, since there's no answer to read.

:::terminal
```bash
ampctl table prune 1
```

```
⚠ This will schedule non-canonical segment files for garbage collection (files will be eligible for deletion after 3600s). Continue? [y/N] y
✓ Revision 1 pruned (0 non-canonical segment files scheduled for GC, deletion in 3600s)
```
:::

The Quickstart's data had no reorgs, so there was nothing to prune. With `--json`, `files_scheduled` is how many files
were taken out of the revision, and `before_block` appears when you pass `--before-block`:

:::terminal
```bash
ampctl table prune 1 --before-block 24000050 --gc-delay 7200 --force --json
```

```json
{ "location_id": 1, "files_scheduled": 0, "gc_delay_secs": 7200, "before_block": 24000050 }
```
:::

The files leave the revision at once, so [`histogram`](/clis/ampctl/table#ampctl-table-histogram) stops counting them. They stay in
storage until the dataset's garbage collection job runs, about every hour, after the delay. This can't be undone.

:::warning
A [streaming query](/querying/streaming-queries) that was reading a fork can't resume once its segments are pruned.
If clients may still need to recover from a recent reorg, pass `--before-block` to keep the recent forks.
:::

A revision whose writer is still running fails, with exit code 1. Stop it with
[`ampctl dataset stop`](/clis/ampctl/dataset#ampctl-dataset-stop) first:

```
✗ revision with location ID '7' has an active writer job; stop the job before pruning
```

## `ampctl table delete`

Deletes an inactive revision, and Amp's record of its files. The files stay in storage.

```
ampctl table delete [OPTIONS] LOCATION_ID
```

| Argument / flag | Type    | Default  | Description                                      |
| --------------- | ------- | -------- | ------------------------------------------------ |
| `LOCATION_ID`   | integer | required | The revision's location ID, like `5`.            |
| `-f`, `--force` | flag    | off      | Deletes without asking first. Use it in scripts. |

Its alias is `ampctl table rm`.

Without `--force`, `delete` asks first. Any answer but `y` or `yes` deletes nothing and prints
`→ Deletion cancelled`, with exit code 0, and so does a script without `--force`. The question says the dataset can't
be queried after deletion, but only an inactive revision can be deleted, and queries don't read those: what you lose is
the option to activate this revision again.

:::terminal
```bash
ampctl table delete 5
```

```
⚠ This revision's dataset can't be queried after deletion. Delete revision 5? [y/N] y
✓ Revision 5 deleted
```
:::

With `--json`, it prints the revision's location ID, like `{"location_id":5}`. The revision's files are still in its
directory, so registering and restoring the directory again gets it back, with a new location ID:

:::terminal
```bash
ampctl table register acme/eth_mainnet@1.0.0 blocks acme/eth_mainnet/blocks/imported
```

```
✓ Revision registered for table blocks in dataset acme/eth_mainnet@1.0.0 (location_id: 6)
```
:::

To delete the files too, [truncate](/clis/ampctl/table#ampctl-table-truncate) the revision instead.

### Errors

* `✗ revision with location ID '1' is active and cannot be deleted`: activate another revision of the table, or
  [deactivate](/clis/ampctl/table#ampctl-table-deactivate) it, first.
* `✗ revision with location ID '7' has an active writer job; stop the job before deleting`: the job writing to the
  revision still runs. Stop it with [`ampctl dataset stop`](/clis/ampctl/dataset#ampctl-dataset-stop) first.
* `✗ revision with location ID '7' not found`: no revision has that location ID, maybe because it's already deleted.

## `ampctl table truncate`

Deletes an inactive revision's files from storage, then the revision itself. This can't be undone.

```
ampctl table truncate [OPTIONS] LOCATION_ID
```

| Argument / flag               | Type    | Default  | Description                                                                 |
| ----------------------------- | ------- | -------- | --------------------------------------------------------------------------- |
| `LOCATION_ID`                 | integer | required | The revision's location ID, like `6`.                                       |
| `-f`, `--force`               | flag    | off      | Truncates without asking first. Use it in scripts.                          |
| `--concurrency <CONCURRENCY>` | integer | `10`     | How many files to delete at once, like `--concurrency 20`. `0` counts as 1. |

Without `--force`, `truncate` asks first. Any answer but `y` or `yes` deletes nothing and prints
`→ Truncation cancelled`, with exit code 0, and so does a script without `--force`.

Here, it deletes the copy that the [`delete`](/clis/ampctl/table#ampctl-table-delete) example registered again as revision 6. `truncate`
deletes only the files a revision has recorded, so restore it first:

```bash
ampctl table restore 6
ampctl table truncate 6
```

With `--json`, it prints the revision's location ID and how many files it deleted, like
`{"location_id":6,"files_deleted":1}`.

Files in the directory that [`restore`](/clis/ampctl/table#ampctl-table-restore) never recorded, and files that
[`prune`](/clis/ampctl/table#ampctl-table-prune) already took out of the revision, stay in storage, and so does the directory. If
`truncate` fails partway, run it again: it continues with the files that are left.

Its errors are the same as [`delete`'s](/clis/ampctl/table#ampctl-table-delete), ending in `cannot be truncated` and
`before truncating`.
