SQL Fundamentals Quiz
Practise SQL fundamentals with original query questions and explanations, then retry missed answers across portable SQL and PostgreSQL 18.Practice status
{{ summaryLine }}
{{ quizIssue }}
{{ seedNotice }}
{{ quizSetupValidation }}
{{ progressStatusLine }}
Question {{ quizCursor + 1 }} of {{ questionCount }}
{{ currentQuestion.stem }}
{{ currentQuestion.accessible_clue }}
Answer recorded. Correctness and explanations will appear after you choose View results.
{{ currentResultRow.feedback }}
{{ currentResultRow.explanation }}
Source: {{ currentResultRow.source.reference }} · {{ currentResultRow.source.version }} · {{ currentResultRow.source.license }}
Review what to practice next
{{ resultLead }}
{{ learningReviewTitle }}
{{ learningReviewLine }}
Missed answer review
-
{{ item.prompt }}
Your answer: {{ item.selected_answer_label }}
Correct answer: {{ item.correct_answer_label }}
{{ item.explanation }}
Source: {{ item.source.label }} · {{ item.source.version }} · {{ item.source.license }}
Topic performance
Which SQL topics need another look? Counts describe only the questions answered in this round, not overall proficiency.
Loading topic-performance chart…
{{ quizChartExportStatus }}
Answer ledger
| Question ID | Prompt | Topic | Your answer | Correct answer | Outcome | Explanation | Source | Copy |
|---|---|---|---|---|---|---|---|---|
| {{ row.question_id }} | {{ row.prompt }} | {{ row.category_label }} | {{ row.selected_answer_label }} | {{ row.correct_answer_label }} | {{ row.outcome_label }} | {{ row.explanation }} | {{ row.source ? `${row.source.label} · ${row.source.version} · ${row.source.license}` : '—' }} |
{{ quizLedgerExportStatus }}
A customer with three orders can appear three times in a query result. That may be correct, yet counting those rows as three different customers would give the wrong answer. SQL reasoning depends on understanding what each result row represents, not just recognising a familiar command.
Structured Query Language (SQL) retrieves and changes information in relational databases. A table holds rows of records and columns of values, such as an order identifier, a customer identifier and a quantity. A query can choose columns, keep certain rows, combine related tables or calculate summaries. Choosing fewer columns does not, by itself, remove rows, and combining tables can increase the number of rows returned.
- Predicate
- A condition tested against data, such as whether a quantity is positive. SQL conditions can be true, false or unknown.
- Aggregate
- A calculation across several rows, such as a count, sum or average. Grouping calculates a separate summary for each group.
- NULL
- A marker for a missing or unknown value. A missing quantity is different from a known quantity of zero.
For an inventory report, filtering individual stock rows and filtering category totals answer different questions. Removing low-quantity rows before adding quantities changes the totals themselves. Keeping only categories whose completed totals exceed a threshold leaves the underlying rows available for that calculation. This distinction explains why row filters and group filters are not interchangeable.
Missing values require similar care. Counting all stock records can give a different answer from counting records with a known quantity. An average of known quantities does not treat missing observations as zero. A customer with no matching order also needs different treatment from a customer whose order has a recorded quantity of zero. Those distinctions affect reports even when every SQL statement is syntactically valid.
Result order is another source of mistakes. A table is not a spreadsheet with a dependable first row. A query needs an explicit ordering when sequence matters, and tied values need a further ordering column when their relative position matters. Removing duplicates does not establish a sort order or prove that a join used the intended relationship.
Data changes add consequences beyond an incorrect report. An update without a row condition can affect an entire table. Keys and constraints protect relationships and allowed values, while a transaction groups changes that can be committed together or rolled back before commitment. Learning to predict an affected row is useful preparation, but real changes still require checking the database, the selected rows and the surrounding transaction.
SQL products share many concepts but differ in syntax, defaults and text-comparison rules. A dialect is a product's particular form of SQL, so a familiar-looking statement still needs to be read under the stated product and assumptions. SQL knowledge practice is educational; recognising a correct answer does not establish the ability to design, test or safely operate a production database.
How to Use This Tool:
Predict the answer from the fictional data in each question. The quiz contains 36 original text questions with four choices each. Every sample starts independently, including data-change examples. No SQL is executed and no database is connected.
- Select a Dialect profile. Portable core draws from 32 questions on the stated shared concepts. PostgreSQL 18 + core also includes four labelled dialect questions, giving 36 before other filters are applied.
-
Narrow Query activity, SQL topic and Difficulty to the material you want to practise. The defaults include read and data-change concepts, all topics and mixed difficulty. Basics and Applied reasoning are authored study groupings, not measured proficiency levels.
If Start practice is disabled because no questions match, broaden the filters. For example, Dialect differences requires PostgreSQL 18 + core; Read-only queries does not match Writes & integrity. Choosing All topics or Mixed difficulty can restore a supported combination.
- Choose Question count and Feedback timing. The initial round has 8 questions with Explain after each answer. Available counts are 1, 4, 8, 12 and 20 where they fit, plus the selected pool's full size. Narrow pools can offer fewer questions. Review at the end of the round records answers without displaying correctness or explanations until the final review.
- Enter an optional Replay seed under Advanced, then select Start practice. A blank seed uses a fixed default. Surrounding spaces are ignored; more than 128 characters after trimming produces a notice and uses the default. Keeping the profile, question count, feedback timing, seed and question-bank version unchanged reproduces the questions and option order. Questions do not repeat within a round.
- Choose one answer after checking the query and its stated assumptions. Selecting an option records and locks it for that attempt. Use Next question to continue and View results after the last answer. There is no skipped-question or early-finish result. Begin the final review with the explanations for any missed answers.
Interpreting Results:
During a round, Practice status and the progress percentage describe questions answered. Reaching 100% progress means every question has a response, not that every response is correct. The completed headline instead shows correct answers out of the round's question count.
The Missed answer review gives your choice, the correct choice and the explanation. The Answer ledger also includes questions you answered correctly, making it useful for checking guesses. Topic performance shows counts of Correct and Missed answers in sampled topics. A short round need not balance topics, and an untested topic is not rated. Review focus identifies the category with the most misses, not a measured overall weakness.
- Retry missed starts a new attempt containing only incorrect answers from the completed round. Its smaller question count is a new denominator, not a revision of the earlier score.
- Replay same seed starts the same questions and option order with answers cleared. Try a new seed changes the selection seed but can still repeat previously seen questions.
- Perfect round means no misses in that attempt. There is then no missed-question retry. Broader practice is needed before drawing conclusions about topics absent from the round.
The bank is curated, not exhaustive, and does not assess query optimisation, advanced window queries or recursive queries. Its questions are original learning material, not official vendor questions or a certification test. Compare rounds only with their topic mix, difficulty, size and feedback timing in mind.
Technical Details:
SQL query results follow rules about which rows are available, which conditions hold and when rows become groups. For a basic SELECT, a logical reading order explains those results without assuming a particular physical execution plan.
Reading a query in logical order
The clauses are written in SQL's required syntax order, but reasoning from the input rows towards the final result prevents several common mistakes.
| Clause or operation | Effect on the result |
|---|---|
FROM and JOIN |
Establish the input rows and matching row combinations. |
WHERE |
Keep qualifying individual rows before grouping. |
GROUP BY and aggregates |
Form groups and calculate their summaries. An ungrouped aggregate treats the input as one aggregate group. |
HAVING |
Keep qualifying groups after their aggregate values have been determined. |
SELECT |
Produce the requested columns or expressions for each remaining row or group. |
DISTINCT |
Remove duplicate output rows, considering the complete selected row. |
ORDER BY |
Sort the output. Later sort expressions resolve ties in earlier ones. |
LIMIT, in PostgreSQL questions |
Restrict how many result rows are returned. |
For a category total, WHERE qty > 0 excludes stock rows before summation. HAVING SUM(qty) > 5 instead tests the completed group total. If all rows of a category disappear before grouping, that category does not automatically produce a zero-valued summary row.
NULL and condition boundaries
Ordinary scalar comparisons involving NULL produce unknown, including NULL = NULL. To find a missing quantity, use qty IS NULL, not qty = NULL. Unknown is treated differently when selecting rows and when checking a constraint.
| Condition result | WHERE |
CHECK alone |
|---|---|---|
| True | Keep the row. | Constraint satisfied. |
| False | Discard the row. | Constraint violated. |
| Unknown | Discard the row. | Constraint satisfied. |
Consequently, CHECK (qty > 0) does not prohibit NULL by itself. A separate NOT NULL constraint is needed when a quantity must be present. This does not mean that other constraints on the row are bypassed.
A strict comparison such as qty > 4 excludes 4. qty BETWEEN 4 AND 7 includes both 4 and 7, equivalent to qty >= 4 AND qty <= 7. Parentheses determine how combined conditions apply. In category = 'A' AND (qty = 4 OR qty = 0), belonging to category A remains necessary for either quantity alternative.
Counting rows, known values and empty inputs
The input to an aggregate is the set of rows remaining at that point in the query. A count over joined rows therefore counts those joined rows, not necessarily distinct people or products. The following rules distinguish counting records from calculating with known values.
| Expression | What it uses | Empty-input result |
|---|---|---|
COUNT(*) |
Every input row, regardless of missing column values. | 0 |
COUNT(qty) |
Rows with a non-NULL quantity, including a known zero. | 0 |
SUM(qty) |
The sum of non-NULL quantities. | NULL |
AVG(qty) |
The sum of known quantities divided by their count. | NULL |
For quantities 4, 7, NULL and 0, the row count is 4, the known-quantity count is 3 and the sum is 11. For a separate set of measurements 2, 4 and NULL, the average is 3 because only two values contribute to its denominator. Excluding a missing value is not the same operation as replacing it with zero.
Without GROUP BY, an aggregate query still produces one aggregate row from empty input unless HAVING removes it. A sum over only NULL quantities also remains NULL. A group containing a known zero, however, has a value to sum and can correctly produce zero.
Joins and set operations
An INNER JOIN produces one row per matching pair. A LEFT JOIN also retains each unmatched left row, filling the right-hand columns with NULL. Neither promises one result row per left row when several right rows match. A CROSS JOIN pairs every row from one input with every row from the other, so its row count is the product of the two input counts.
For a left join, a condition in ON decides which right rows match. A condition in WHERE tests the rows after that join, including rows with NULL in the right-hand columns. This is why moving a right-table condition between the two clauses can remove an otherwise preserved person.
Set operations combine complete query results rather than matching related records. Their inputs need the same number of columns with compatible corresponding types.
| Operation | Result rule |
|---|---|
UNION |
Combine both results and remove duplicate rows. |
UNION ALL |
Combine both results and keep duplicate rows. |
EXCEPT |
Return distinct rows from the left result that do not appear in the right result. |
Duplicate removal is not arithmetic addition. If each input contains one row with the same number, UNION keeps one such row, whereas UNION ALL keeps two. None of these operations alone guarantees presentation order.
Writes, integrity and transactions
An explicit column list in INSERT determines how supplied values are assigned, even when that list differs from the table's declared column order. UPDATE changes existing rows that satisfy its condition, and DELETE removes matching rows rather than the table definition. Without a WHERE filter, an UPDATE or DELETE targets every row. In the stated four-row stock example with no triggers, assigning a constant quantity of 8 updates all four rows, including the previously missing quantity.
A standard single-column PRIMARY KEY requires unique, non-NULL values; it does not require consecutive integers. In the stated order example, its non-NULL customer foreign key must match a referenced customer key. It does not create a missing customer automatically. These rules concern data integrity, while the earlier truth table explains why a positive-value CHECK does not also guarantee that a value exists.
A transaction can make several data changes one commit-or-rollback operation. ROLLBACK before COMMIT discards its uncommitted changes. The balance example assumes an isolated change from 20 to 15 and no other changes, so rollback leaves the stored balance at 20. This is not a promise that a committed change can later be undone with rollback.
PostgreSQL 18 assumptions
The four dialect questions use the following PostgreSQL 18 behaviours. Their separate grouping does not imply that every listed feature is exclusive to PostgreSQL, or that all other SQL products behave identically.
| Subject | Stated behaviour and limit |
|---|---|
| Default NULL ordering | ORDER BY v ASC places NULL after non-NULL values by default. For 2, NULL and 1, the result is 1, 2, NULL. An explicit NULLS FIRST or NULLS LAST specifies the placement. |
| Case-insensitive patterns | ILIKE performs case-insensitive pattern matching according to the active locale. The question uses ordinary English text. The operator is a PostgreSQL extension, not universally portable SQL syntax. |
| A limited result without ordering | LIMIT 3 over 20 available rows returns three rows, but without ORDER BY neither their membership nor their sequence is guaranteed. Repeatable selection needs ordering that resolves ties. |
| Values from a write | An INSERT with RETURNING id can expose the inserted row's identifier. It does not undo the insertion or return every pre-existing identifier. |
The question bank is dated 11 September 2026 and labels its SQL references as PostgreSQL 18, verified 11 September 2026. That reference date is not a live compatibility check. Portable-core questions cover their stated semantics, not every product, schema, locale setting or dialect variation.
Practice scoring and completion
Each correct choice earns 1 point and each incorrect choice earns 0. Every question has equal weight. The correct-answer fraction and completion percentage answer different questions.
C is the number correct, A is the number answered and N is the fixed question count for that attempt. C, A and N are counts of questions and are integers satisfying 0 ≤ C ≤ A ≤ N, with N ≥ 1. Points count correct answers; accuracy and progress are percentages. Possible points equal N, and the completed headline shows C/N. During a partial attempt, unanswered questions remain in N but are neither incorrect answers nor missed-retry items. Completion requires all N responses. There are no penalties, weighted topics, pass thresholds or proficiency bands.
Fractional percentages are retained in the calculation. Only the visible progress label rounds to the nearest whole percent, with half-percent ties upward; the progress label therefore displays 13% for one answer out of eight, whose exact progress is 12.5%. The correct/total headline avoids that rounding ambiguity.
For a four-question round with three correct answers, the score is 3/4, equivalent to 75%, while completed progress is 100%. If the missed question is then answered correctly in Retry missed, the new score is 1/1. It describes the one-question retry and does not turn the original attempt into 4/4.
Privacy Notes:
Answers are scored in the browser. Attempt data in the URL is not encrypted or private progress storage: the page address carries the practice setup, seed, recorded answers and position in the round. This includes partial attempts. A recipient of that address can restore the saved choices, so a practice link should not be treated as a blank or private challenge.
- Saved addresses can enter browser history or be transmitted when loaded or shared. Avoid personal or confidential text in a replay seed.
- Change setup clears the current attempt and its saved address state. It cannot remove links already copied or shared, and there is no account-based progress history.
- An incompatible or damaged saved attempt is rejected. If Saved attempt unavailable appears, choose a supported setup and start a new round rather than relying on the old score.
- Loading the topic chart may need a network connection. Local scoring is not a guarantee of complete offline operation, zero network requests or any particular site-wide logging or retention policy.
Worked Examples:
A category disappears before grouping
In an Aggregates question, stock contains category A quantities 4 and 7, and category B quantities NULL and 0. For SELECT category, COUNT(*) FROM stock WHERE qty > 0 GROUP BY category ORDER BY category;, the correct choice is one row with category A and count 2. The row filter first retains the two positive quantities. Neither B row survives, so grouping produces no B row at all, not a B row with count zero. A missed answer here points to the order of filtering and grouping rather than an arithmetic error.
Keeping a person who has no qualifying order
The Joins & sets questions use people 1, 2 and 3, with orders 10 and 11 belonging to person 1 and order 12 belonging to person 2. For a left join whose ON condition includes both p.id = o.person_id and o.id > 10, the correct pairs are (1, 11), (2, 12) and (3, NULL). Order 10 is not a qualifying match, while person 3 remains as an unmatched left row. In the companion question, placing o.id > 10 in WHERE leaves only people 1 and 2 because the missing order value does not pass that filter. The correction is to distinguish matching orders from filtering completed join rows.
References:
- PostgreSQL 18 — SELECT, PostgreSQL Global Development Group.
- PostgreSQL 18 — Table Expressions, PostgreSQL Global Development Group.
- PostgreSQL 18 — Comparison Functions and Operators, PostgreSQL Global Development Group.
- PostgreSQL 18 — Aggregate Functions, PostgreSQL Global Development Group.
- PostgreSQL 18 — Constraints, PostgreSQL Global Development Group.
- PostgreSQL 18 — Inserting Data, PostgreSQL Global Development Group.
- PostgreSQL 18 — Updating Data, PostgreSQL Global Development Group.
- PostgreSQL 18 — Deleting Data, PostgreSQL Global Development Group.
- PostgreSQL 18 — Transactions, PostgreSQL Global Development Group.
- PostgreSQL 18 — Pattern Matching, PostgreSQL Global Development Group.
- PostgreSQL 18 — Returning Data from Modified Rows, PostgreSQL Global Development Group.