Understanding query results

Lesson 7 of 10 · 15 min0/4 checked in practice
Objective

By the end of this lesson you can predict the shape and column names of a result, recognise data types and NULL in the output, and add a named calculated column.

Why it matters: A query that runs is not necessarily a query that's right. Analysts check every result: the number of rows, what each column is called and what type it holds, and whether blanks are real. That habit catches most mistakes before a manager does.

Dataset: Starter shop. Examples run in the editor on the right.

Every query returns a result set: a temporary table with its own columns and rows. Before trusting it, read four things:

  1. Shape: how many columns and how many rows. Without a filter, the row count equals the rows of the table you read; the column count equals the items in your SELECT list.
  2. Column names: each result column has a name. Usually it's the source column's name; you can choose your own with AS.
  3. Data types: numbers, text, dates and true/false values behave differently, and the result keeps each column's type.
  4. NULLs: an empty-looking cell shown as NULL means no value, never zero.

Calculated columns

A SELECT list can contain more than column names. It can contain expressions: calculations that PostgreSQL works out for every row. Arithmetic uses +, -, * (multiply) and / (divide).

Saudi VAT is 15 %, so a price including VAT is price * 1.15. PostgreSQL computes it row by row, using each product's own price.

ExamplePrices with VAT
SELECT product_name,
       price,
       price * 1.15 AS price_with_vat
FROM products;

10 rows, 3 columns. The third column doesn't exist in the table; it's calculated per row (89.00 becomes 102.3500). The extra decimal places appear because multiplying two decimals keeps all their digits. AS price_with_vat names the new column.

Name every calculated column

Without AS, PostgreSQL invents a name for a calculation: usually ?column?. Two unnamed calculations both get ?column?, and nobody downstream (a spreadsheet, a dashboard, a colleague, or the SQL Quest grader) can tell what they mean. The rule: every calculated column gets an alias.

Aliases follow the identifier rules from the last lesson: lower-case snake_case, no quotes needed. AS is optional in PostgreSQL (price * 1.15 price_with_vat works), but writing it makes the intent obvious.

SELECT expression AS column_alias
FROM table_name;
Give a calculated column a clear name with AS.

Types shape results

The type of a calculated column follows from its inputs:

  • number × number gives a number;
  • a date plus a whole number gives a later date (days are added);
  • a date minus a date gives a whole number of days;
  • text joined to text with || gives text.

The example uses all three non-numeric rules. DATE '2025-12-31' writes a date literal: a fixed date value.

ExampleDates and text in calculations
SELECT customer_name,
       joined_on,
       joined_on + 30 AS welcome_offer_ends,
       DATE '2025-12-31' - joined_on AS days_as_customer_by_year_end,
       'Ships to ' || city AS delivery_label
FROM customers;

welcome_offer_ends is a date 30 days after joining; days_as_customer_by_year_end is a whole number. Look at Reem Al-Zahrani's delivery_label: it is NULL, because her city is NULL and joining text to an unknown value gives an unknown result.

Row order is not part of the answer

The rows of a result come back in whatever order PostgreSQL finds convenient. Small tables often look sorted by id, but that isn't promised, and it changes as tables grow. If order matters, you must ask for it with ORDER BY (covered later in this track and in depth in the next one). That's also why SQL Quest compares unordered results as a set of rows unless a task asks for a specific order.

Quick check
Quick check

SELECT product_name, price * stock FROM products; What is the second column called in the result?

Now practise
4 exercises on real data, checked in your browser (practice).