Help improve SovranCode?

Google Analytics can measure anonymous usage after you choose Allow. Essential account and progress features work either way.

SovranCode
SQL: Query, Model, and Analyze Data Your First SELECT Query
This device
Course contentsYour First SELECT Query · 32 topics

Relational foundations

Databases, SQL, and the relational modelTables, rows, columns, and schemasData types and NULLPrimary keys, foreign keys, and relationships

Reading and filtering data

Your first SELECT queryConditions with WHERESorting, limiting, and distinct valuesText, dates, patterns, and conditional results

Reports, aggregation, and analytics

Aggregate functionsGROUP BY and HAVINGWindow functionsCommon table expressions

Combining related data

INNER, LEFT, RIGHT, and FULL joinsPlannedSelf joins and many-to-many dataPlannedSubqueries and correlated subqueriesPlannedUNION, INTERSECT, and EXCEPTPlanned

Designing reliable schemas

CREATE TABLE and schema designPlannedConstraints and data integrityPlannedNormalization and intentional denormalizationPlannedViews and materialized viewsPlanned

Writing and protecting data

INSERT, UPDATE, and DELETEPlannedUpserts and conflict handlingPlannedTransactions and savepointsPlannedIsolation, locks, and concurrencyPlanned

Performance and administration

Indexes and access pathsPlannedEXPLAIN and query plansPlannedQuery tuning patternsPlannedBackups, restores, and migrationsPlanned

Security and production workflow

Users, roles, and least privilegePlannedPreventing SQL injectionPlannedStored procedures, functions, and triggersPlannedProduction data projectPlanned
SQL: Query, Model, and Analyze Data12 complete · 20 planned

Relational foundations

Databases, SQL, and the relational modelTables, rows, columns, and schemasData types and NULLPrimary keys, foreign keys, and relationships

Reading and filtering data

Your first SELECT queryConditions with WHERESorting, limiting, and distinct valuesText, dates, patterns, and conditional results

Reports, aggregation, and analytics

Aggregate functionsGROUP BY and HAVINGWindow functionsCommon table expressions

Combining related data

INNER, LEFT, RIGHT, and FULL joinsPlannedSelf joins and many-to-many dataPlannedSubqueries and correlated subqueriesPlannedUNION, INTERSECT, and EXCEPTPlanned

Designing reliable schemas

CREATE TABLE and schema designPlannedConstraints and data integrityPlannedNormalization and intentional denormalizationPlannedViews and materialized viewsPlanned

Writing and protecting data

INSERT, UPDATE, and DELETEPlannedUpserts and conflict handlingPlannedTransactions and savepointsPlannedIsolation, locks, and concurrencyPlanned

Performance and administration

Indexes and access pathsPlannedEXPLAIN and query plansPlannedQuery tuning patternsPlannedBackups, restores, and migrationsPlanned

Security and production workflow

Users, roles, and least privilegePlannedPreventing SQL injectionPlannedStored procedures, functions, and triggersPlannedProduction data projectPlanned
PREVIOUS LESSONPrimary Keys, Foreign Keys, and Relationships
NEXT LESSONConditions with WHERE
Reading and filtering data · Lesson 05 110 min

Your First SELECT Query

A SELECT query turns stored rows into a result shaped for a question. You choose the source table with FROM, choose the output columns with SELECT, and can rename or calculate values without changing the stored data.

What you will leave with

You will be able to write a readable SELECT ... FROM ... query, choose explicit columns instead of a wildcard for stable application output, name result columns with AS, calculate new values, distinguish a result column from a stored column, and explain why an unsorted result has no guaranteed order.

A query has a source and an output shape

SourceFROM identifies the table whose rows you want to read.
ProjectionSELECT chooses which values appear in each output row.
AliasesAS gives the returned columns names useful to readers and callers.
ReviewCheck the output columns and rows against the question you meant to answer.
STORED TABLEcoursescourse_id · title · category · duration_minutes · price_cents

Four course rows are available to read.

QUERYSELECT title, duration_minutesFROM courses;

The query requests two values from each row.

RESULTtitle · duration_minutesSQL Foundations · 90

The result has two columns and four rows.

Read a table with SELECT and FROM

SELECT title, duration_minutes FROM courses; asks for the title and duration of each course row. The comma separates output expressions; FROM courses names the source table; the semicolon ends the statement. SQL keywords are conventionally written in uppercase to make them easy to scan, but SQLite does not require uppercase keywords.

The result is a new table-shaped answer. It does not remove other columns from courses, edit any row, or save a new table. Run the query, then compare the result headings with the five columns in the table definition.

SQL BROWSER RUNNER

Run your first SELECT query

Create four course rows and request just title and duration from each one.

CREATE TABLE courses (
  course_id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  category TEXT NOT NULL,
  duration_minutes INTEGER NOT NULL,
  price_cents INTEGER NOT NULL
);

INSERT INTO courses (course_id, title, category, duration_minutes, price_cents) VALUES
  (101, 'SQL Foundations', 'Data', 90, 0),
  (102, 'Data Modeling', 'Data', 120, 2550),
  (103, 'CSS Layouts', 'Web', 75, 0),
  (104, 'JavaScript DOM', 'Web', 105, 1899);

SELECT title, duration_minutes
FROM courses;
QUERY OUTPUT
Edit the query, predict the rows it will return, then run it.

Each run starts a fresh SQLite database in an isolated browser worker. Your edited SQL is saved on this device, but the database and its rows are discarded after the run.

Try this next: Swap duration_minutes for category. Predict the two result headings before you run again.

Read the query in two passes

First find FROM to learn where the rows come from. Then read the SELECT list to learn what each output row contains. SQL writes these clauses in the opposite order, so this habit makes a new query easier to understand.

Projection chooses columns, not rows

Choosing columns is called projection. Every selected source column becomes a column in the result, in the order you list it. At this stage, all four course rows remain because the query has no condition. Filtering rows with WHERE is the next lesson; adding or removing a projected column does not filter a row.

SQL BROWSER RUNNER

Change the result shape

Return the identity, title, and category for every course, in that order.

CREATE TABLE courses (
  course_id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  category TEXT NOT NULL,
  duration_minutes INTEGER NOT NULL,
  price_cents INTEGER NOT NULL
);

INSERT INTO courses (course_id, title, category, duration_minutes, price_cents) VALUES
  (101, 'SQL Foundations', 'Data', 90, 0),
  (102, 'Data Modeling', 'Data', 120, 2550),
  (103, 'CSS Layouts', 'Web', 75, 0),
  (104, 'JavaScript DOM', 'Web', 105, 1899);

SELECT course_id, title, category
FROM courses;
QUERY OUTPUT
Edit the query, predict the rows it will return, then run it.

Each run starts a fresh SQLite database in an isolated browser worker. Your edited SQL is saved on this device, but the database and its rows are discarded after the run.

Try this next: Move category before title, then remove course_id. How do the headings change? How many rows remain?

Use SELECT * to inspect, then name the contract

SELECT * returns every column from the source table. It is useful when you are exploring a small table, but an application usually needs an explicit list. If a new column is added later, * silently changes the output shape. It can also return large or sensitive columns the caller did not need. Explicit columns make the query’s purpose and result contract reviewable.

SQL BROWSER RUNNER

Compare a wildcard with explicit columns

Run both queries and compare their headings and values in the output panel.

CREATE TABLE courses (
  course_id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  category TEXT NOT NULL,
  duration_minutes INTEGER NOT NULL,
  price_cents INTEGER NOT NULL
);

INSERT INTO courses (course_id, title, category, duration_minutes, price_cents) VALUES
  (101, 'SQL Foundations', 'Data', 90, 0),
  (102, 'Data Modeling', 'Data', 120, 2550),
  (103, 'CSS Layouts', 'Web', 75, 0),
  (104, 'JavaScript DOM', 'Web', 105, 1899);

-- Compare this exploratory query with the explicit version below.
SELECT *
FROM courses;

SELECT course_id, title, price_cents
FROM courses;
QUERY OUTPUT
Edit the query, predict the rows it will return, then run it.

Each run starts a fresh SQLite database in an isolated browser worker. Your edited SQL is saved on this device, but the database and its rows are discarded after the run.

Try this next: Comment out either SELECT to inspect one result at a time. Restore both, then add category to the explicit list.

The runner shows every result set

The examples create a fresh SQLite database on each run. When a script has two SELECT statements, the output panel prints both results in statement order. Comment out one query when you want to focus on the other.

Aliases name the output, not the stored column

An alias follows an expression: title AS course_title. The result heading becomes course_title, while the column in the table remains title. Aliases are especially useful when a report needs friendly names or a calculated value needs an understandable heading. Use short, descriptive identifiers; spaces in aliases require dialect-specific quoting and are best avoided in application-facing results.

SQL BROWSER RUNNER

Give result columns useful names

Rename three output columns without changing the table schema.

CREATE TABLE courses (
  course_id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  category TEXT NOT NULL,
  duration_minutes INTEGER NOT NULL,
  price_cents INTEGER NOT NULL
);

INSERT INTO courses (course_id, title, category, duration_minutes, price_cents) VALUES
  (101, 'SQL Foundations', 'Data', 90, 0),
  (102, 'Data Modeling', 'Data', 120, 2550),
  (103, 'CSS Layouts', 'Web', 75, 0),
  (104, 'JavaScript DOM', 'Web', 105, 1899);

SELECT
  title AS course_title,
  duration_minutes AS minutes_to_complete,
  price_cents AS price_in_cents
FROM courses;
QUERY OUTPUT
Edit the query, predict the rows it will return, then run it.

Each run starts a fresh SQLite database in an isolated browser worker. Your edited SQL is saved on this device, but the database and its rows are discarded after the run.

Try this next: Change course_title to name. Verify the result heading changes, then query title again to confirm the stored column is still title.

SELECT can calculate a value for each row

The select list can contain expressions as well as column names. price_cents / 100.0 AS price_dollars converts cents for display. The decimal 100.0 matters in this SQLite example: using an integer divisor can produce integer division and lose the cents. duration_minutes + 15 computes a hypothetical break-adjusted duration. Neither calculation writes back to the table.

SQL BROWSER RUNNER

Compute named result values

Compare stored cents and minutes with calculated dollars and break-adjusted minutes.

CREATE TABLE courses (
  course_id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  category TEXT NOT NULL,
  duration_minutes INTEGER NOT NULL,
  price_cents INTEGER NOT NULL
);

INSERT INTO courses (course_id, title, category, duration_minutes, price_cents) VALUES
  (101, 'SQL Foundations', 'Data', 90, 0),
  (102, 'Data Modeling', 'Data', 120, 2550),
  (103, 'CSS Layouts', 'Web', 75, 0),
  (104, 'JavaScript DOM', 'Web', 105, 1899);

SELECT
  title,
  price_cents,
  price_cents / 100.0 AS price_dollars,
  duration_minutes + 15 AS minutes_with_break
FROM courses;
QUERY OUTPUT
Edit the query, predict the rows it will return, then run it.

Each run starts a fresh SQLite database in an isolated browser worker. Your edited SQL is saved on this device, but the database and its rows are discarded after the run.

Try this next: Change the break from 15 to 20 minutes. Add duration_minutes / 60.0 AS duration_hours and compare the result.

Literals and NULL can appear in a result

A select list may include a literal such as 'SovranCode' AS provider. The same label appears in every output row because it comes from the query, not the table. NULL AS reviewed_on represents an unknown or absent value. The expression price_cents = 0 AS is_free evaluates a comparison for each row; SQLite displays the boolean result as 1 or 0. Other database systems may display boolean values differently.

SQL BROWSER RUNNER

Add labels and a simple comparison

Add output values that are computed from literals or a condition, while leaving stored rows untouched.

CREATE TABLE courses (
  course_id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  category TEXT NOT NULL,
  duration_minutes INTEGER NOT NULL,
  price_cents INTEGER NOT NULL
);

INSERT INTO courses (course_id, title, category, duration_minutes, price_cents) VALUES
  (101, 'SQL Foundations', 'Data', 90, 0),
  (102, 'Data Modeling', 'Data', 120, 2550),
  (103, 'CSS Layouts', 'Web', 75, 0),
  (104, 'JavaScript DOM', 'Web', 105, 1899);

SELECT
  title,
  'SovranCode' AS provider,
  NULL AS reviewed_on,
  price_cents = 0 AS is_free
FROM courses;
QUERY OUTPUT
Edit the query, predict the rows it will return, then run it.

Each run starts a fresh SQLite database in an isolated browser worker. Your edited SQL is saved on this device, but the database and its rows are discarded after the run.

Try this next: Change the provider label, then add SELECT * FROM courses as a second statement to compare the unchanged stored columns.

Result order is not promised without ORDER BY

Small examples often appear in insertion order, which can create a false sense of certainty. A SELECT query without ORDER BY does not promise row order, even when rows appear stable in this runner. Indexes, plans, or data changes can alter it. In this lesson, compare result shapes and values as sets of rows. Sorting and limiting results are taught later in this module.

Common first-query mistakes

SELECT title courses;

Missing FROM

Name the source table with FROM courses before asking SQLite to read its columns.

SELECT title category FROM courses;

Missing comma

Separate expressions with commas. Without one, SQL may interpret the second identifier as an alias instead.

SELECT * in an API response

Unstable output

Choose only the columns the caller needs so a schema change does not silently expand the response.

Looks sorted in the demo

Assumed row order

A repeated-looking order is still not a guarantee. Use ORDER BY when order matters.

Independent lab: build a course card feed

Using the four seeded courses, return one result row per course with course_id, a course_name alias, duration in hours, price in dollars, and a constant provider label. The starter query already runs. Rebuild it from a blank SELECT list, then add a price_label or is_free expression of your own. Explain which values are stored and which exist only in the result.

SQL BROWSER RUNNER

Shape a course card result

Create an application-ready output without altering the source table.

CREATE TABLE courses (
  course_id INTEGER PRIMARY KEY,
  title TEXT NOT NULL,
  category TEXT NOT NULL,
  duration_minutes INTEGER NOT NULL,
  price_cents INTEGER NOT NULL
);

INSERT INTO courses (course_id, title, category, duration_minutes, price_cents) VALUES
  (101, 'SQL Foundations', 'Data', 90, 0),
  (102, 'Data Modeling', 'Data', 120, 2550),
  (103, 'CSS Layouts', 'Web', 75, 0),
  (104, 'JavaScript DOM', 'Web', 105, 1899);

-- Build a course card feed. Keep one row per course.
-- Include course_id, a readable course name, duration in hours,
-- and a price in dollars. Add a provider label.
SELECT
  course_id,
  title AS course_name,
  duration_minutes / 60.0 AS duration_hours,
  price_cents / 100.0 AS price_dollars,
  'SovranCode' AS provider
FROM courses;
QUERY OUTPUT
Edit the query, predict the rows it will return, then run it.

Each run starts a fresh SQLite database in an isolated browser worker. Your edited SQL is saved on this device, but the database and its rows are discarded after the run.

Try this next: Rebuild the five-column result yourself. Add an is_free expression, then confirm SELECT * still shows only the original five stored columns.

Lab review criteria

The result should have four rows and explicit, meaningful headings. Money should use a decimal divisor, duration should use 60.0, and every derived value should have an alias. The underlying courses table should still have its original five columns.

Lesson review

FROM names the source table. SELECT shapes the result by choosing columns, literals, or expressions. AS labels output columns without renaming stored fields. A wildcard is useful for exploration, but explicit columns make stable, narrow output. Projection changes columns, not the number of source rows; the next lessons will add filtering, sorting, and limiting.

  • I can write a readable SELECT ... FROM ... query.
  • I can predict the columns and row count of a projection.
  • I can explain why an explicit column list is useful for application output.
  • I can use AS to name result columns without changing the table.
  • I can calculate a named value and distinguish it from stored data.
  • I know that a result has no guaranteed row order without ORDER BY.
KNOWLEDGE CHECK

Check your first SELECT model

Answer all eight questions, then use the explanations and runnable examples to revisit any weak spot.

01What does FROM courses identify in SELECT title FROM courses?
02How many rows does SELECT title FROM courses return when courses has four rows and no WHERE clause?
03Which statement returns title and category as two separate result columns?
04What does title AS course_name change?
05Why prefer an explicit column list over SELECT * in application code?
06In SQLite, why use price_cents / 100.0 rather than price_cents / 100 for a dollar value?
07What happens to the courses table after SELECT duration_minutes + 15 AS adjusted_minutes FROM courses?
08What row order can you rely on without ORDER BY?
PREVIOUS LESSONPrimary Keys, Foreign Keys, and Relationships
NEXT LESSONConditions with WHERE
ON THIS PAGEYour First SELECT QueryLesson mapFirst queryProjectionWildcardAliasesExpressionsLiterals and NULLResult orderCommon mistakesIndependent labLesson reviewKnowledge check
Course contents