First half: short demonstrations and T1–T6. Second half: your official Lab 2 in Northshore Coffee. The practice questions below are new; they do not replace the numbered Canvas questions.
Keep these questions beside the SQL playground. Say the selected database name before every switch. Use Rick & Morty for T1–T4, then switch once to IMDb Movies for T5–T6. Coffee is an optional bridge before the official lab.
Predict on paper, run one statement, inspect the result, then explain one row or boundary. Partners switch writer/checker roles after each question. Keep SQL as text.
Detailed recap and demonstration examples
Open each topic as it comes up. The worked example teaches the tool; the T questions below ask you to transfer it.
1. SELECT, FROM and the shape of a result · Rick & Morty
One scripts row is one dialogue record, not one character or episode. Repeated speaker names are expected. First identify the table and what one row means; then choose the columns that answer the question.
SELECT chooses output columns and their order. FROM identifies the source table. SELECT * is useful for a first inspection; explicit columns make the intended answer clearer. Selecting fewer columns does not itself remove rows.
AS changes an output heading for this query only. It neither renames the stored column nor updates its values. FROM scripts AS s gives the table a temporary query nickname; s.characterName still refers to the original column.
Write text values in straight single quotes, identifiers normally unquoted, and aliases with spaces in double quotes. Commas separate SELECT expressions; do not put a comma immediately before FROM. Finish each statement with a semicolon.
For these single-table queries, reason through FROM, then WHERE, then SELECT, DISTINCT, ORDER BY and LIMIT. This is a useful logical model, not a promise about the engine’s physical execution plan.
Choose a readable sample
SELECT id, characterName, episodeName
FROM scripts
ORDER BY id
LIMIT 3;
Give the output and table temporary names
SELECT s.id, s.characterName AS speaker,
s.episodeName AS "Episode title"
FROM scripts AS s
ORDER BY s.id
LIMIT 3;
2. Calculations, text and DISTINCT · Rick & Morty
A SELECT expression is calculated for each surviving row. You can return the original value beside a hypothetical value to check the arithmetic. +, -, *, / and % mean addition, subtraction, multiplication, division and integer remainder. Parentheses control arithmetic order.
SQLite divides two integers using integer division: 5 / 2 returns 2. Use 5 / 2.0 for 2.5. For movie hours, runtime / 60.0 avoids truncation. These SELECT calculations do not change stored data.
Use || to concatenate text in SQLite, including an explicit separator such as ' / '. + is arithmetic, not text concatenation. An expression involving NULL usually remains NULL; an absent value is not automatically an empty string.
DISTINCT removes duplicate output rows. DISTINCT characterName returns different speaker labels; DISTINCT characterName, episodeNumber returns distinct pairs. Adding id usually prevents duplicate removal because the id is unique.
Use output aliases in ORDER BY. For WHERE, repeat the original expression or use the source column. SQLite permits some aliases in WHERE as an extension, but relying on that is confusing and not portable.
A hypothetical edit, without changing stored words
SELECT id, wordCount,
wordCount + 2 AS words_after_intro,
characterName || ' / ' || episodeName AS label
FROM scripts ORDER BY id LIMIT 3;
Different speaker labels
SELECT DISTINCT characterName
FROM scripts
ORDER BY characterName;
Check integer division directly
SELECT 5 / 2 AS integer_result,
5 / 2.0 AS decimal_result,
17 % 5 AS remainder;
3. WHERE: exact values, lists and boundaries · Rick & Morty
WHERE retains a row only when its condition is true. You may filter on a column that you do not display. Filtering rows and choosing columns are separate decisions.
= means equal; <> and != mean not equal. > and < exclude the boundary; >= and <= include it. Translate “more than” differently from “at least”, and “under” differently from “at most”. Write numeric thresholds without quotes.
IN is an exact-value list for one expression: characterName IN ('Rick', 'Morty') means Rick OR Morty. It is not pattern matching. Every OR condition must be a complete comparison: characterName = 'Rick' OR 'Morty' is not a reliable way to ask this question.
BETWEEN 8 AND 12 includes both 8 and 12. Its equivalent is wordCount >= 8 AND wordCount <= 12. NOT BETWEEN excludes known values inside that range, but it does not automatically include missing values.
This database contains selected episodes, not every episode. An empty result does not prove the SQL is broken: check the values that actually exist. Do not invent a table called characters or a column called season.
Both a speaker and a word-count boundary
SELECT id, characterName, wordCount
FROM scripts
WHERE characterName = 'Summer' AND wordCount >= 10
ORDER BY id;
Two exact speakers in an inclusive range
SELECT id, characterName, wordCount
FROM scripts
WHERE characterName IN ('Beth', 'Jerry')
AND wordCount BETWEEN 8 AND 12
ORDER BY id;
4. LIKE: match the text, not its meaning · Rick & Morty
Use = for an exact stored value and LIKE for a text pattern. characterName = 'Rick%' looks for the literal percent sign; it does not mean “starts with Rick”.
LIKE 'Rick%' matches a prefix. LIKE '%Rick' matches a suffix. LIKE '%Rick%' matches Rick anywhere. % matches zero or more characters, so Rick itself also matches Rick%.
_ matches exactly one character. LIKE 'R___' matches four-character values beginning with R. The underscore is a wildcard only inside a LIKE pattern; underscores in names such as imdb_score are ordinary identifier characters.
The classroom SQLite defaults make LIKE case-insensitive for ASCII letters (Rick and rick), while ordinary text equality here uses the default case-sensitive comparison. Do not assume those rules across every language, collation or database.
LIKE does not understand synonyms, whole words or genre categories. A movie genre field can contain a combined label such as Crime, Drama: = 'Drama' and LIKE '%Drama%' ask different questions.
To put an apostrophe in SQL text, double it: 'Schindler''s List'. To search for a literal wildcard, choose an escape character: LIKE '%!_%' ESCAPE '!' finds an underscore. These are optional reference details.
Find episode labels containing a word
SELECT DISTINCT episodeName
FROM scripts
WHERE episodeName LIKE '%Dog%'
ORDER BY episodeName;
Four-character speaker labels beginning with R
SELECT DISTINCT characterName
FROM scripts
WHERE characterName LIKE 'R___'
ORDER BY characterName;
5. AND, OR, NOT and parentheses · IMDb Movies
AND requires both tests to be true. OR requires at least one. NOT reverses true/false, but NOT unknown remains unknown when NULL is involved. Predict a specific row before running the full query.
AND binds more tightly than OR. year >= 2000 AND runtime <= 100 OR imdb_score >= 8.5 means (recent AND short) OR highly rated: it can admit older highly rated movies.
If every movie must be recent, write year >= 2000 AND (runtime <= 100 OR imdb_score >= 8.5). Parentheses express the business rule; they are not decorative.
Use the real IMDb Movies snapshot here: one movies row is one film. runtime is in minutes; imdb_score is the stored score. This is a historical teaching snapshot, not today’s ratings or a complete census of films.
Validate meaning, not just syntax. A query can run successfully and still include the wrong rows. Explain one qualifying row and invent a boundary case that should fail.
A recent short-or-highly-rated watchlist
SELECT id, title, year, runtime, imdb_score
FROM movies
WHERE year >= 2000
AND (runtime <= 100 OR imdb_score >= 8.5)
ORDER BY id;
Known titles outside a pair of years
SELECT id, title, year
FROM movies
WHERE year NOT IN (1999, 2000)
ORDER BY id LIMIT 5;
6. NULL: unknown is not zero · IMDb Movies
NULL represents missing or unknown data. It differs from 0, an empty string '', and the literal text 'NULL'. A blank-looking result cell is not enough evidence: use a SQL test.
Use IS NULL and IS NOT NULL. gross = NULL and gross <> NULL evaluate to unknown, so WHERE keeps no rows from those tests. They can run with no syntax error while answering the wrong question.
A missing gross value does not mean a film earned no money. A missing meta_score does not mean a score of zero. Report the missingness instead of inventing a value.
Be explicit when a rule must include missing values: meta_score < 60 OR meta_score IS NULL. NOT IN is especially tricky if its list contains NULL; avoid that construction in today’s work.
COALESCE can supply a display fallback, but replacing missing numbers with zero changes their meaning. It is a later tool, not a substitute for deciding what the missing value means.
Find an evidence gap
SELECT id, title, year, meta_score
FROM movies
WHERE meta_score IS NULL AND year >= 2010
ORDER BY id;
Keep only recorded box-office values
SELECT id, title, gross
FROM movies
WHERE gross IS NOT NULL
ORDER BY id LIMIT 5;
7. Predictable previews and debugging · IMDb Movies
ORDER BY controls display order: ASC (the default) is smallest first; DESC is largest first. Add a unique id as a final tie-breaker when you need repeatable selection among equal scores. This is a short preview of next week, not an extra Lab 2 requirement.
LIMIT 5 returns at most five rows after filtering and ordering. Without ORDER BY, the chosen rows are unspecified; that does not mean SQLite randomly samples them. OFFSET skips rows in that ordered sequence. DISTINCT does not guarantee sorting.
The playground displays up to 200 result rows and labels a truncated result. A displayed count of 200 is not necessarily the total number of matching records. Narrow the question or use an instructor-provided COUNT(*) check; aggregation is not today’s required topic.
Use Quick schema or the database reference to confirm names. Autocomplete helps with table and column names; it does not write the reasoning for you. Run one SQL statement at a time. The sqlite3 shell command .schema is not SQL and will not run here.
If a query fails, check the selected database, FROM table, spelling, commas and quotes. If it runs but seems wrong, check boundaries, parentheses, NULL and patterns. Start simple and add one condition at a time.
Save SQL as text before leaving. A screenshot is useful for discussion but does not satisfy the official Lab 2 requirement to submit runnable query text in the Word report. SELECT does not edit the source data.
The five highest stored scores, with a stable tie-break
SELECT id, title, imdb_score
FROM movies
ORDER BY imdb_score DESC, id
LIMIT 5;
A second page of a stable title list
SELECT id, title
FROM movies
ORDER BY id
LIMIT 5 OFFSET 5;
Use the names in this database
scripts has 1,905 dialogue records. movies has 1,000 film records. They are separate databases and cannot be joined in one playground query.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
T2 · Rick & Morty
Make a useful display label
For the first four records by id, return id, wordCount, wordCount * 3 AS triple_words, and characterName || ' / ' || episodeName AS label. Explain what remains stored afterward.
Explain: Check one multiplication by hand. Does the expression alter wordCount?
Small hint
Use || for text and * for multiplication. Keep the original wordCount visible.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
T3 · Rick & Morty
Find concise lines in two episodes
Across the included seasons, find records from episodeNumber 2 or 4 whose wordCount is between 8 and 12, inclusive. Show id, episodeNumber, characterName and wordCount, ordered by id.
Explain: Would counts of 8 and 12 pass? Would an episode 3 record with 10 words pass?
Small hint
Combine one exact list and one inclusive range with AND.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
T5 · IMDb Movies
A watchlist with two alternatives
Find films released from 2010 onward that either last no more than 95 minutes OR have imdb_score at least 8.5. Show id, title, year, runtime and imdb_score, ordered by id.
Explain: Would a 1994 film with a score of 9.3 qualify? Explain where the parentheses belong.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
Optional pair practice · If time permits
P1 · IMDb Movies
One genre or a combined genre label?
Write two queries returning id, title and genre: first where genre is exactly Drama, then where genre contains Drama. Order each by id. Identify a film found only by the second query.
Explain: Why might the second list be larger? The display may stop at 200 rows; do not treat that as the complete count.
Small hint
Run one statement at a time. Compare whole-value equality with a substring pattern.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
P2 · IMDb Movies
Repair a query that runs
Someone wants movies from 1999 or 2000 and writes: SELECT id, title, year FROM movies WHERE year = 1999 OR 2000; Explain the problem, repair it, and order the result by id.
Explain: SQLite treats the bare nonzero number 2000 as true. Why is a successful Run not a correctness check?
Small hint
Use IN, or repeat the column comparison on both sides of OR.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
P3 · Rick & Morty
Four letters versus a prefix
List distinct characterName values beginning with R. Then list distinct characterName values that start with R and contain exactly four characters. Sort both alphabetically.
Explain: Which wildcard controls an exact character count, and which allows any length?
Small hint
One underscore stands for one character; the initial R already contributes one.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
P4 · IMDb Movies
Keep a precise runtime calculation
For movies with id 1 through 5, return id, title, runtime and runtime / 60.0 AS hours. Order by id. Compare with runtime / 60, then explain which version preserves fractions.
Explain: Are calculated hours a permanent new field? How would you verify one result by hand?
Small hint
One decimal operand prevents integer division here.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
C2 · Northshore Coffee
A different location question
Show id, name, city and has_drive_thru for shops in Tofte or Beaver Bay. Order by id and explain the 1/0 flag without assuming all shops in a city have the same value.
Explain: Which part selects rows, and which part decides the displayed columns?
Small hint
This is a new exact-list question, not a copied numbered Lab 2 question.
Record: your prediction → SQL text → one result row or counterexample → your explanation.
Second half: the official Lab 2
Switch to Northshore Coffee. Follow Q1–Q15, Check the AI, the client transfer and personal reflections in the official handout. This page’s T/P/C labels are practice labels, not assignment numbers.
One writes, one checks; switch roles. Each student submits independently using the Canvas Word report template. Paste SQL as text, the result and a one-line answer. Save as Lab02_LastName.docx. The handout states September 15 at 2:00 PM; confirm the submission window in Canvas.
Exit ticket: explain = versus LIKE, why = NULL fails, and one boundary or parentheses error you caught.
Aligned to the original Week 2 notes, Pre-Lab 2 and Lab 2. Reference: SQLite SELECT and SQLite expressions. Lecture examples and answer checks run against the classroom files, not an invented schema.