Read items from a table or a GSI. A SELECT with a partition-key equality executes as a native Query; without one it's a Scan that reads — and bills — every item, flagged amber before it runs. Every example below is quotable: the link icon copies a permanent URL to that exact query.
Syntax
sql
SELECT [DISTINCT] column | expr [AS name], … -- or SELECT VALUE exprFROM "table" | "table"."index"[WHERE predicates][GROUP BY keys [HAVING condition]][ORDER BY key [ASC|DESC] [NULLS FIRST|LAST]][LIMIT n] [OFFSET n]
Quote table names — especially namespaced ones containing dots ("stage.Users"). Keywords read case-blind; attribute names are case-sensitive on the wire. Guides: First queries for projection and computed columns, Targeted reads for the WHERE reference.
Use cases
Fetch one item by its keyNative
The bread-and-butter point read — profile lookups, order details, config rows. The complete key makes it a one-item Query.
sql
SELECT * FROM "stage.Users"WHERE pk = 'USER#42' AND sk = 'PROFILE'
Executes asQuery · KeyConditionExpression: pk = 'USER#42' AND sk = 'PROFILE'
Partition-key equality plus the sort key: DynamoDB touches exactly one item.
List a partition by sort-key prefixNative
All events for one order, newest first — begins_with on the queried sort key narrows the key condition itself, so only the matching slice is read.
sql
SELECT * FROM "stage.Outbox"WHERE pk = 'Outbox#123' AND begins_with(sk, 'EVT#')ORDER BY sk DESCLIMIT 25
Executes asQuery · KeyConditionExpression: pk = 'Outbox#123' AND begins_with(sk, 'EVT#')
ORDER BY on the queried sort key stays native — DynamoDB returns index order.
Look up by a non-key attribute via a GSINative
Find users by organization when the base table is keyed by user id — the FROM "table"."index" form reads the alternate key path.
sql
SELECT * FROM "stage.Users"."ByOrg"WHERE OrgId = 'ORG#kanject'
A GSI obeys the same rule: equality on the index's partition key is a Query; filtering the index on a non-key attribute is still a Scan of the index.
Shape columns with expressionsLowered
Build display values in the query — document paths, || concatenation, and CASE relabelling, all computed client-side after the read and disclosed.
sql
SELECT Name || ' <' || email || '>' AS contact, address.city, CASE Status WHEN 1 THEN 'Pending' WHEN 2 THEN 'Shipped' ELSE Status END AS statusFROM "stage.Users" WHERE pk = 'USER#42'
Executes asQuery · Projection: Name, email, address, Status → shaped client-side per fetched row
Client-side shaping changes what you see, never what DynamoDB reads or bills — the WHERE controls the bill.
Count the rows in one partitionLowered
How many events does this order have? The fold has no native form — the partition drains as a Query, then COUNT computes client-side.
sql
SELECT COUNT(*) AS total FROM "stage.Outbox"WHERE pk = 'Outbox#123'