DSM
50 XP
25 minsBeginner50 XP

SELECT & FROM

A production orders table can hold 40 columns and half a billion rows — but the report your manager wants needs exactly three columns. SELECT is how you carve precisely what you need out of a mountain of data, and it's the single most-typed word in any data career. By the end of this lesson you'll be writing queries that pick columns, compute new ones, rename them cleanly, and strip out duplicates.

What you'll learn

  • Write SELECT ... FROM queries that return specific columns from a table
  • Explain what projection means and why SELECT * is discouraged in production
  • Compute derived columns with arithmetic expressions inside SELECT
  • Rename columns and expressions using AS aliases
  • Apply DISTINCT to remove duplicate rows from a result

What

SELECT names the columns you want back; FROM names the table to read them from. Together they form the smallest complete SQL query. Aliases (AS) rename columns in your output, and DISTINCT removes duplicate rows from the result.

Why

Pulling every column of every row wastes time, memory, and money — cloud warehouses literally bill by data scanned. Choosing exactly the columns you need (called projection) makes queries faster, cheaper, and easier to read.

Where it's used

Every dashboard tile, every report, every machine-learning training set starts with a SELECT. It is the verb of data analysis.

Where this runs in production

NetflixSelecting features for recommendations

Netflix analysts query viewing-history tables with billions of rows, selecting just the columns a model needs — profile_id, title_id, watch_seconds — rather than dragging entire rows across the network.

AirbnbListing quality dashboards

Airbnb's internal dashboards run SELECT queries against listings data, projecting price, rating, and location columns and aliasing computed fields like nightly_revenue for clean chart labels.

DoorDashDistinct active merchants

DoorDash measures marketplace health with queries like SELECT DISTINCT store_id FROM deliveries — collapsing millions of delivery rows into the unique set of stores that fulfilled at least one order.

Theory

The core ideas, in plain language.

A SQL query is a request for data, and its two mandatory parts are SELECT and FROM. FROM names the table to read; SELECT lists the columns to return, separated by commas. Choosing a subset of columns has a formal name: projection — you project the table onto just the columns you care about.
Analogy: The restaurant-order analogy

Querying a table is like ordering at a restaurant. FROM is choosing the restaurant (which table), and SELECT is your order (which dishes/columns). Saying SELECT * is telling the kitchen 'bring me everything on the menu' — occasionally useful for exploring, wasteful and slow as a habit. The analogy breaks down in one way: the database never runs out of stock — it returns every matching row, every time.

-- customers(customer_id, name, email, country, signup_date)
SELECT name, country
FROM customers;

This asks for exactly two columns from the customers table. The result is itself a table — same number of rows as customers, but only two columns wide. Column order in your output follows the order you list them in SELECT, not their order in the table.

Key Concept
The result of a query is a table

Every SELECT returns rows and columns — a temporary result table. This is why SQL composes so well: anything that produces a table can feed something that consumes one. That idea powers subqueries and CTEs later in the course.

SELECT can do more than copy columns — it can compute. Write an arithmetic expression using column names and SQL evaluates it for every row. This is how derived values like revenue (quantity * unit_price) are born, without changing anything in the stored table.
-- order_items(order_item_id, order_id, product_id, quantity, unit_price)
SELECT
  order_id,
  quantity * unit_price AS line_revenue
FROM order_items;

quantity * unit_price is computed per row. AS line_revenue gives the computed column a readable name — an alias. Without the alias, PostgreSQL would label the column '?column?', which helps nobody reading your report. The AS keyword itself is optional (quantity * unit_price line_revenue also works), but writing it makes the intent unmissable.

Key Concept
DISTINCT removes duplicate rows

SELECT DISTINCT country FROM customers returns each country once, no matter how many customers live there. DISTINCT applies to the whole selected row: SELECT DISTINCT country, city de-duplicates on the combination — two rows survive if they differ in either column.

Watch out
SELECT * in production code

SELECT * is fine for exploring a new table interactively. In saved queries, dashboards, and pipelines it's a liability: it scans and transfers columns you don't need (cloud warehouses like BigQuery bill by bytes scanned), and if someone adds a column to the table, your downstream code silently receives a different shape of data. List your columns explicitly.

Visual Learning

See the concept, then explore it.

Anatomy of a SELECT Query

Click each stage to see what it contributes. The query flows from the full stored table to your trimmed, renamed, de-duplicated result.

Worked Examples

Watch it built up, one line at a time.

Very EasySelect two columns

The marketing team wants a simple list of customer names and countries for a newsletter segment.

Step 1 of 2

SELECT lists the two columns marketing asked for, separated by a comma. FROM names the table. The semicolon ends the statement.

Code
01SELECT name, country
02FROM customers;
Practice Coding

Your turn — write the code.

Your task

You're an analyst at an online electronics shop. The products table holds the catalog. Build a price sheet: product name (labeled 'product'), the unit price, and a new column 'price_with_vat' that adds 20% VAT (unit_price * 1.20). Fill in the blanks.

Expected output
 product        | unit_price | price_with_vat
----------------+------------+----------------
 Wireless Mouse | 25.00      | 30.0000
 USB-C Hub      | 49.50      | 59.4000
 Laptop Stand   | 32.00      | 38.4000
(3 rows)

Write your solution in the editor on the right, then hit Run.

Exercises

Prove it. Reach 80% to complete the lesson.

Mastery Gate0% / 80% required
Easy0/2 solved

What does 'projection' mean in SQL?

Which query returns each customer's name under the output column header 'client'?

Medium0/3 solved

The orders table has 1,000 rows from 340 different customers. How many rows does SELECT DISTINCT customer_id FROM orders; return?

ScenarioA teammate's scheduled dashboard query uses SELECT * FROM orders. The data engineering team then adds four large JSON columns to orders for a new feature. The next morning, the dashboard job runs 6× slower and the warehouse bill spikes.

What is the root cause, and the correct fix?

Using order_items(order_item_id, order_id, product_id, quantity, unit_price), write a query returning order_id and a computed column named line_total (quantity multiplied by unit_price), for all rows.

Correct columns:Returns exactly order_id and the computed column
Alias applied:The computed column is named line_total via AS
Correct arithmetic:line_total equals quantity * unit_price for every row
Hard0/1 solved

customers has rows: (Egypt, Cairo), (Egypt, Cairo), (Egypt, Alexandria) in its (country, city) columns. What does SELECT DISTINCT country, city FROM customers; return?

Complete 80% more exercises to unlock.
Interview Prep

How this shows up in real interviews.

Walk me through what SELECT and FROM do in a SQL query.

Show model answer

FROM names the table the database reads, and SELECT lists which columns come back in the result — an operation called projection. The result of any query is itself a table of rows and columns, which is what makes SQL composable. SELECT can also compute new columns with expressions, like quantity * unit_price, and rename any output column with an AS alias. A query as small as SELECT name FROM customers; is complete and useful — those two clauses are the foundation everything else builds on.

Why is SELECT * discouraged in production queries, and when is it acceptable?

Show model answer

SELECT * fetches every column, which creates three problems in production. First, cost and speed: columnar warehouses bill and perform based on the columns you scan, so pulling 90 columns when you need 3 can multiply cost dramatically. Second, fragility: when someone adds columns to the table, every SELECT * query silently changes shape, which can break downstream code, inflate dashboards, or leak newly added sensitive columns. Third, readability: an explicit column list documents exactly what the query depends on. SELECT * is perfectly acceptable for interactive exploration — peeking at an unfamiliar table's contents — and in a few idioms like EXISTS subqueries where the column list is ignored. My rule: star while exploring, explicit columns in anything saved or scheduled.

How does DISTINCT behave with multiple columns, and what performance consideration comes with it on large tables?

Show model answer

DISTINCT operates on the entire selected row, not any individual column: SELECT DISTINCT country, city keeps every unique combination of the pair, so two rows survive if they differ in either value. A frequent misconception is that DISTINCT binds to the first column it appears next to — it doesn't; it's a modifier on the whole SELECT. Performance-wise, the database must determine uniqueness across all returned rows, typically by hashing or sorting the full result set, which can be expensive on tables with hundreds of millions of rows. If I only need distinct values of grouped data I'm aggregating anyway, GROUP BY expresses that intent directly. I also treat an unexpected need for DISTINCT as a smell: in join-heavy queries it often papers over accidental row duplication from a fan-out, and the right fix is usually the join logic, not de-duplication at the end.

Common Mistakes to Avoid

1) Forgetting commas between column names in SELECT — SELECT name country silently treats country as an alias for name, giving you one mislabeled column instead of two. 2) Using single quotes for aliases or column names — in standard SQL, 'text' in single quotes is a string value; identifiers with spaces need double quotes: AS "Customer Name". 3) Assuming DISTINCT applies only to the column written right after it — it de-duplicates the entire selected row. 4) Expecting integer division to keep decimals — 5400 / 3600 is 1 in PostgreSQL; write 3600.0 to force decimal division. 5) Shipping SELECT * in saved queries and dashboards, which bloats cost and breaks silently when the table gains columns.

Ask the AI Tutor

Try these prompts in the AI Tutor panel: • 'ELI5: what does SELECT actually do, using a menu analogy different from the lesson's?' • 'Quiz me: five questions about aliases and DISTINCT.' • 'Show me a case where forgetting a comma in the SELECT list produces a wrong-but-running query.' • 'Explain why SELECT is written first but evaluated near the end.' • 'Interview mode: ask me why SELECT * is risky in production and grade my answer.'

Glossary

SELECT — the clause listing which columns (or expressions) a query returns. FROM — the clause naming the table to read. Projection — returning a chosen subset of columns. Result set — the table of rows and columns a query produces. Expression — a computation in the SELECT list, like quantity * unit_price. Alias — an output name assigned with AS to a column or expression. Identifier — the name of a table or column; quoted with double quotes when it contains spaces. String literal — a text value in single quotes, like 'Egypt'. DISTINCT — a modifier that removes duplicate rows from the result. SELECT * — shorthand for 'all columns'; fine for exploration, risky in production. Integer division — dividing two integers yields an integer in PostgreSQL; use a decimal like 3600.0 to keep fractions.

Recommended Resources

• Docs: PostgreSQL manual — 'Queries: Select Lists' covers projection, expressions, and aliasing from the source. • Read: your warehouse vendor's pricing page (e.g. BigQuery on-demand pricing) to see why bytes scanned — and therefore SELECT * — is a real money question. • Practice: on any sample database, write five queries that each return exactly the columns needed for an imaginary stakeholder request — no more. • Next in DSM: WHERE & Filtering, where you stop returning every row and start choosing which rows qualify.

Recap

✓ SELECT lists the columns to return; FROM names the table — together they form a complete query. ✓ Projection (choosing columns) changes the width of the result, never the row count. ✓ SELECT can compute derived columns per row with expressions like quantity * unit_price. ✓ AS gives columns and expressions readable output names; double quotes protect aliases with spaces. ✓ DISTINCT removes duplicate rows, comparing the entire selected row — not just one column. ✓ Prefer explicit column lists over SELECT * in anything saved or scheduled: cheaper, faster, and stable as schemas grow. Next up: WHERE & Filtering. You can now choose your columns — but every query so far returned all rows. Next you'll write predicates that keep only the rows you want: orders over $100, customers in Egypt, emails matching a pattern — and you'll meet SQL's famously tricky NULL logic.

scratchpad — preview this lesson's challenge anytime
query.sqlSQL
Ready
Output

Run your code to see the output here.