Skip to content
LakeBench
ProblemsCommunityPricing
Sign inStart practicing

SQL & Analytical Warehousing

Progress0/29
x

Understanding Data

  • What is data?8m
  • What is a database?8m
  • Tables, rows, and columns10m
  • Primary keys and foreign keys10m

Relational core

  • Relational basics8m
  • NULL handling10m
  • Aggregations & grouping10m
  • Multi-table joins12m
  • Subqueries & CTEs10m

Windows, cleaning & opsPreview

  • Window functions (the DE benchmark)Free14m
  • Data cleaning & string/date manipulation10m
  • CASE expressions10m
  • Deduplication & incremental upserts12m
  • Indexing, partitioning & optimization12m

Advanced Querying

  • Set operations: UNION, INTERSECT, EXCEPT10m
  • Recursive CTEs for hierarchical data12m
  • Querying semi-structured JSON12m
  • Pivoting and unpivoting12m

Warehouse & Dimensional Modeling

  • OLTP vs OLAP mental model10m
  • Star schema: facts, dimensions, grain14m
  • Surrogate keys & conformed dimensions12m
  • Slowly Changing Dimensions Type 1 / 2 / 316m
  • Additive, semi-additive, and non-additive facts12m
  • Normalization vs denormalization for analytics12m

Performance & Production SQL

  • Query plans: hash, merge, nested-loop14m
  • Partitioning & clustering in real warehouses12m
  • Views vs materialized views10m
  • PK / FK / CHECK, and how warehouses relax them12m
  • Capstone: model a star from orders18m
Back to track
  1. Learn
  2. SQL & Analytical Warehousing
  3. Relational core
  4. Relational basics

Lesson 5 of 29 · Theory first, then run it

Relational basics

sqlbeginner8 min

Overview

SELECT names columns, WHERE filters rows, DISTINCT removes duplicates, LIMIT caps output.

On this page7 sections›
  1. 1The table we keep using
  2. 2What we need from it
  3. 3Trace it step by step
  4. 4Same table, next cut
  5. 5Common beginner questions
  6. 6What comes next
  7. 7Practice

The table we keep using

Source data

Before running any query, you should know what the source table looks like. Here is a sample of the orders table:

Sample rows from the orders table. Each row is one order placed by a customer.

order_iduser_idorder_statusorder_totalcreated_at
O0001U100paid149.002026-08-01 09:15:00
O0002U101cancelled42.502026-08-01 10:30:00
O0003U102paid88.002026-08-02 14:22:00
O0004U100pending210.752026-08-03 08:45:00
O0005U103paid55.202026-08-03 16:10:00

SQL (Structured Query Language) is the language you use to ask questions of data stored in tables. Think of a table like a spreadsheet: it has rows (individual records) and columns (properties of each record). When you write a SQL query, you are telling the database exactly which rows and columns you want to see.

The most basic SQL statement is SELECT, which picks which columns to show. FROM tells the database which table to look in. WHERE filters out rows that do not match a condition. Together, these three clauses form the foundation of every SQL query you will ever write.

Formal definition: a SELECT statement is a declarative request that specifies a projection (columns), a source (table), and optional predicates (filters). The database engine decides how to retrieve the data efficiently. You describe what you want, not how to get it.

What we need from it

Imagine you work at an e-commerce company with millions of orders stored in a database. Your manager asks: 'How many orders were cancelled last month?' Without SQL, you would need to export the entire orders table to a spreadsheet and manually filter and count. With SQL, you write a single query that returns the answer in seconds.

Data engineers use SELECT queries to inspect source tables before building pipelines. If you cannot read the raw data correctly, every downstream transformation will be wrong. These basic clauses are your first tool for validating that data loaded correctly, checking for unexpected values, and previewing what a pipeline will produce.

A query without INSERT, UPDATE, or DELETE does not change the table. Reading data is always safe. This makes SELECT the ideal tool for exploration and debugging.

Trace it step by step

The SQL track starts in an already-loaded warehouse: tables sit on the shelves in this browser tab, and you query them instead of standing up a cluster.
Warehouse tables in this browser tab. The diagrams below show how each operator changes the result.

SQL is written in a specific order: SELECT, FROM, WHERE, ORDER BY, LIMIT. But the engine processes it differently. It starts with FROM (find the table), then WHERE (filter rows), then SELECT (pick columns), then ORDER BY (sort), then LIMIT (cap rows). Understanding this execution order helps you predict what your query will return.

How the engine processes your query
FROM ordersWHERE filterSELECT columnsDISTINCTORDER BYLIMIT

The engine reads FROM first, then filters, then projects columns, then sorts, then limits.

The warehouse in this tab already holds several tables: orders, order_items, ecommerce_events, payments, and customers. Each table represents a different business entity. The orders table has columns like order_id, user_id, order_status, order_total, and created_at.

Same table, next cut

Example 1: Basic SELECT

The simplest query picks a few columns from a table. The AS keyword is not needed here because we are selecting existing column names directly.

Run the example below in this tab. Read the input, follow the code, then check the output matches what you expect.

SQLProject three columns from the orders table
SELECT
  order_id,
  order_status,
  order_total
FROM orders;

Result: only the three requested columns appear. All rows are included because there is no WHERE.

order_idorder_statusorder_total
O0001paid149.00
O0002cancelled42.50
O0003paid88.00
O0004pending210.75
O0005paid55.20

Example 2: Filtering with WHERE

WHERE lets you keep only the rows that match a condition. Text values must be wrapped in single quotes. Numbers do not need quotes.

SQLReturn only cancelled orders
SELECT order_id, order_total
FROM orders
WHERE order_status = 'cancelled';

Result: only rows where order_status equals 'cancelled' survive the filter.

order_idorder_total
O000242.50

You can combine conditions with AND (both must be true) or OR (either can be true). You can also use comparison operators: greater than (>), less than (<), greater than or equal (>=), not equal (<>).

SQLPaid orders above 80 in value
SELECT order_id, order_total, order_status
FROM orders
WHERE order_status = 'paid'
  AND order_total > 80;

Result: both conditions must be true for a row to appear.

order_idorder_totalorder_status
O0001149.00paid
O000388.00paid

Example 3: Sorting and limiting

ORDER BY sorts the result. DESC means descending (highest first). ASC means ascending (lowest first, and is the default). LIMIT caps how many rows are returned.

SQLTop 3 paid orders by value
SELECT order_id, order_total
FROM orders
WHERE order_status = 'paid'
ORDER BY order_total DESC
LIMIT 3;

Result: paid orders sorted from highest to lowest total, capped at 3 rows.

order_idorder_total
O0001149.00
O000388.00
O000555.20

DISTINCT removes duplicates

DISTINCT removes duplicate result rows. It applies to the entire selected tuple (combination of columns), not just one column. If you SELECT DISTINCT country, device, you get unique country-device pairs.

SQLList all unique status values in the table
SELECT DISTINCT order_status
FROM orders
ORDER BY order_status;

Result: three distinct statuses exist in the orders table.

order_status
cancelled
paid
pending

What if you forget WHERE?

A common mistake is forgetting to add a WHERE clause when you only need a subset of data. Without WHERE, every row in the table is returned. On a production table with millions of rows, this can be slow and expensive.

SQLForgetting WHERE returns everything
-- WRONG: returns ALL orders, not just paid ones
SELECT order_id, order_total
FROM orders;

-- CORRECT: filters to only paid orders
SELECT order_id, order_total
FROM orders
WHERE order_status = 'paid';

Three-valued logic with NULL

NULL means 'unknown' or 'missing'. A comparison like order_status = NULL is always unknown (not true or false). Use IS NULL or IS NOT NULL instead. For example: WHERE paid_at IS NULL finds orders that have not been paid.

SELECT * in production

SELECT * returns every column. Fine while learning, but on a 400-column event table it reads fields you never use and wastes resources. Always name the specific columns you need.

No ORDER BY means no guaranteed order

Without ORDER BY, the database can return rows in any order. Parallel execution and storage changes can alter which rows appear first. Always sort when the order matters.

Every SQL query needs at least SELECT and FROM. The others are optional.

ClauseQuestion it answersRequired?
SELECTWhich columns do I want?Yes, always required
FROMWhich table has the data?Yes, always required
WHEREWhich rows match my condition?No, omit to get all rows
DISTINCTAre there duplicate rows to remove?No, only when needed
ORDER BYWhat order should results be in?No, but recommended
LIMITHow many rows maximum?No, but useful for previews

Copy-paste without reading the output

Run Sample first. If the numbers or row count look wrong, stop and re-read the previous section before changing code.

Common beginner questions

What is the difference between single quotes and double quotes in SQL?

Single quotes wrap text values like 'paid'. Double quotes wrap column or table names that have spaces or reserved words. Most of the time, you only need single quotes.

Why does WHERE come before ORDER BY?

The engine filters first (reduces work), then sorts the remaining rows. If you sorted first and filtered second, the engine would waste time sorting rows it will discard.

Can I use LIMIT without ORDER BY?

Yes, but the rows you get back are unpredictable. Without ORDER BY, the database returns whichever rows it finds first, which might change between runs.

What comes next

Now that you can select, filter, and sort individual rows, the next lesson is NULL: missing values, IS NULL, and COALESCE. Aggregations come right after that, and they skip NULL unless you handle it.

Practice

Run Sample to see paid orders sorted by total. Then complete the exercise: return order_id and order_total for cancelled orders, highest total first, at most 10 rows.

Practicals · load into the editor

After you read the theory, run these in the pane on the right. They execute in this tab, no cluster.

Practice this

Same ideas as interview drills. These challenges open in the studio with a dataset and tests already set up.

  • Filter Engineering salariesInterview-style drill: Filter employees in Engineering earning more than 80000.Studiobeginnersql8 min
  • Salary category bucketsInterview-style drill: CASE WHEN to bucket salaries into Low, Medium, High, Unknown.Studiobeginnersql8 minPro
Rate:
Was this useful?
Primary keys and foreign keysNULL handling