# DELETE — remove items

Remove items — with the same two shapes as `UPDATE`. A `WHERE` naming the **complete primary key** is a native single-item delete; anything looser runs as a **preview-first set-based delete** whose first Run writes nothing. This page is about removing *data*; removing a *table* is [`DROP TABLE`](https://www.kanject.com/docs/dynostudio-create-table/#drop-table), a control-plane statement with a type-the-name confirmation — the two never collide.

## Syntax

```sql
DELETE FROM "table"
WHERE key predicates [AND conditions]
[RETURNING ALL OLD *]
```

`RETURNING ALL OLD *` echoes the item as it was before the delete — the last look you'll get. Read-only stages refuse deletes on every surface. Guide: [Writes & transactions](https://www.kanject.com/docs/dynostudio-partiql-writes/).

## Use cases

### Delete one item by its key

The precise removal — complete key, one native write, first press.

```sql
DELETE FROM "stage.Users"
WHERE pk = 'USER#42' AND sk = 'PROFILE'
```

_Executes as:_ DeleteItem · Key: USER#42/PROFILE

_Quote this example:_ https://www.kanject.com/docs/dynostudio-delete/#delete-one

### Delete and keep a copy of what was removed

Audit trails and undo buffers — the deleted item comes back in the same round trip.

```sql
DELETE FROM "stage.Users"
WHERE pk = 'USER#42' AND sk = 'PROFILE'
RETURNING ALL OLD *
```

_Executes as:_ DeleteItem · ReturnValues: ALL_OLD

_Quote this example:_ https://www.kanject.com/docs/dynostudio-delete/#delete-returning-old

### Sweep stale rows (preview-first)

Clear outbox entries older than 30 days. No key in the `WHERE` → bulk delete: preview the matching rows first, then an unchanged second Run removes them, each write re-checking its predicate atomically.

```sql
DELETE FROM "stage.Outbox"
WHERE CreatedAt < CURRENT_TIMESTAMP - 30
```

_Executes as:_ Preview first → one DeleteItem per row, each re-checking the WHERE as a ConditionExpression

- Capped at 1,000 matched rows — past that it refuses and asks for a narrower WHERE.
- The clock arithmetic folds before the wire: `CURRENT_TIMESTAMP - 30` becomes a literal, disclosed in the strip.

_Quote this example:_ https://www.kanject.com/docs/dynostudio-delete/#sweep-old-rows

## Try it

**Try it · DELETE**

```sql
DELETE FROM "stage.Users"
WHERE pk = 'USER#42' AND sk = 'PROFILE'
RETURNING ALL OLD *
```

_Executes as:_ DeleteItem · stage.Users — Complete key → one native delete; the old item echoes back once.

_Run it live in DynoStudio:_ https://www.kanject.com/dynostudio/

> **Deleting on a schedule? Use TTL instead:** If rows should *age out* rather than be swept, give them a TTL attribute at write time (`'ExpiresAt': unix_now() + 604800`) and let DynamoDB expire them for free — no sweep to run, no read cost to pay. See [INSERT](https://www.kanject.com/docs/dynostudio-insert/#insert-with-ttl) for the quotable example.

Related: [Writes & transactions](https://www.kanject.com/docs/dynostudio-partiql-writes/) · [UPDATE](https://www.kanject.com/docs/dynostudio-update/) · [Transactions](https://www.kanject.com/docs/dynostudio-transactions/) · [Tables, indexes & replicas](https://www.kanject.com/docs/dynostudio-partiql-ddl/) for `DROP TABLE`.

---
_Source: https://www.kanject.com/docs/dynostudio-delete/ · Kanject Docs_
