N054-H3 Tier 4 · Advanced · hard ecommerce · Brightlane

Return a JSON object for product `id = 9` with the keys `'name'` (the product name) and `'warranty_years'` (the warranty term as a JSON number)

Part of JSONB Aggregation (jsonb_agg, json_build_object) in SQL

The problem

Brightlane's product specification API requires the warranty term to appear as a JSON number in the output, not a JSON string.

Write a query to return a JSON object for product id = 9 with the keys 'name' (the product name) and 'warranty_years' (the warranty term as a JSON number).

Assumptions:

  • The products table has one row per product with an id, a name, and an attributes JSONB column.
  • Product id = 9 carries a 'warranty_years' key in its attributes whose value is a JSONB number.
  • In the result JSON object, the 'warranty_years' value must be a JSON number — not a JSON string surrounded by quotes.

Output:

  • A single row with one column, product_spec, containing the JSON document with the keys 'name' and 'warranty_years'.
Schema · ecommerce 5 tables
categories
id integer
name text
parent_id? integer
products
id integer
name text
category_id integer
price numeric
stock_qty integer
attributes? jsonb
order_items
id integer
order_id integer
product_id integer
quantity integer
unit_price numeric
customers
id integer
name text
email text
city? text
country text
created_at timestamptz
is_active boolean
orders
id integer
customer_id integer
ordered_at timestamptz
status text
total_amount numeric

Run previews · Check grades

Write a query, then run it to see results here.

Worked solution Try it yourself first
Solution query
SELECT
  JSON_BUILD_OBJECT(
    'name',
    name,
    'warranty_years',
    (attributes ->> 'warranty_years')::INTEGER
  ) AS product_spec
FROM
  products
WHERE
  id = 9

The shape

attributes->>'warranty_years' returns text, and json_build_object preserves the type of each value it receives, so passing text gives JSON string output. Casting the extraction with ::integer first turns the value into a PostgreSQL integer; json_build_object then writes it as a JSON number. The cast is the entire reason the API gets 3 instead of "3".

Clause by clause

  • SELECT json_build_object('name', name, 'warranty_years', (attributes->>'warranty_years')::integer) AS product_spec builds the document with two keys. The 'name' value comes from the column directly — JSON string out, no cast needed. The 'warranty_years' value extracts the JSONB key as text, then ::integer converts the text to an integer before json_build_object sees it. JSON number out.
  • FROM products reads the product records.
  • WHERE id = 9 narrows the input to the one product whose ID is 9, Meridian T1 Carbon. The function runs once and the query returns one row with product_spec set to { "name": "Meridian T1 Carbon", "warranty_years": 3 }.

Why this and not attributes->'warranty_years'

The -> operator returns JSONB, preserving the source type. If 'warranty_years' is stored as a JSONB number, attributes->'warranty_years' would also give the API 3 as a number, and the cast would be unnecessary. The reason the canonical query goes through ->> and then casts is that the prompt does not promise the source type — only that the value is a JSONB number. The text-then-cast path produces a JSON number from either a JSONB string or a JSONB number storage shape, so it is the robust answer.

The trap

->> always returns text. Passing text to json_build_object produces a JSON string in the output, surrounded by quotes. A reviewer scanning the result for "warranty_years": 3 versus "warranty_years": "3" will catch the missing cast immediately, but the query runs either way — no error, no warning. Any time the JSON output type matters and the source is being pulled through ->>, the cast is mandatory: ::integer for whole numbers, ::numeric for decimals, ::boolean for true/false. Without it, every value the API receives is a string.

You practiced (attributes ->> 'key')::integer inside json_build_object — the cast forces JSON-number output; without it the value would render as a JSON string because ->> returns text.

How you actually get good at SQL

Reading explains SQL. Writing it, over and over with instant feedback, is what makes you fluent.

That's the whole SQLMaxx loop: 600+ real problems, instant AI feedback, mastery you can actually see, and spaced review that won't let you forget.

A stack of SQL practice problem cards, the top card showing an employees table.
615 problems · 66 concepts

Real problems. Not toy examples.

615 hand-built problems spanning all 66 concepts, from basic SELECTs to window functions, built on real schemas and real business questions, the kind you'll actually get asked on the job. Enough reps to make SQL automatic.

A retro computer showing a SQL query marked correct with a green checkmark.
Instant AI feedback

Write a query. Know if it's right in one second.

No copying an answer and hoping it clicked. The AI grader checks your real query against real data, catches exactly what's wrong, and explains the fix in plain English, like a senior analyst reading over your shoulder on every problem.

A circular mastery progress dial filling from blue to green, the SQLMaxx diamond at its center.
Mastery tracking

Stop guessing whether you actually know it.

SQLMaxx tracks every concept and shows you what you've mastered and what's still shaky. Your skills fill in one concept at a time, so 'I think I get joins' becomes something you can prove.

A SQL query editor circled by a blue return arrow with a clock, scheduled to come back for review.
Spaced review

Learn it once. Keep it for good.

Most of what you learn this week fades by next week. So when a concept comes due for review, SQLMaxx hands you a fresh problem to solve from a blank editor, not a flashcard to re-read. A research-backed spaced-repetition algorithm (FSRS) times each return for right before you'd forget, so your SQL is still there months later, when the interview or the job actually needs it.

Practice, feedback, mastery, review. That's the loop that turns reading into real skill.

Start free

No account, no credit card. Start solving in under a minute.