Quiz: Deep Postgres: Pt. 2
Are you SQL Steele? Or a SQL Softie?
Part 2 of 2. Back to Part 1
Welcome to Part 2 of my Deep Postres Quiz!
This quiz covers a mix of familiar and lesser-known PostgreSQL features and gotchas: JOIN, NULL, ANSI SQL, Transactions, Internals, Indexing, Data Sampling… and more!
Good luck! 🍀
Which is not ❌ a valid PostgreSQL JOIN expression?
You knew about CROSS JOIN, right?
Did the JOIN ALL get you thinking about another operation, UNION ALL?
The answer here is JOIN ALL ❌.
The correct JOIN types are:
INNER JOIN(default JOIN)LEFT JOIN(orLEFT OUTER JOIN)RIGHT JOIN(orRIGHT OUTER JOIN)FULL JOIN(orFULL OUTER JOIN)CROSS JOIN(the Cartesian product, unless a laterWHEREclause filters it)
Except for “Depends on side effects” What happens after an error?
BEGIN;UPDATE students SET status = 'alumni' WHERE grade = 12;UPDATE students SET graduation_date = CURRENT_DATE WHERE grade = 12;UPDATE students SET grade = 'GRADUATED'; -- 🚨 Error: type mismatchCOMMIT;When an error occurs here:
- The entire transaction is rolled back
- No changes are committed
- The transaction is marked as failed
To partially commit:
BEGIN;UPDATE ...;SAVEPOINT my_save;UPDATE ...; -- ErrorROLLBACK TO my_save;COMMIT;Which ON condition can PostgreSQL use for a HASH JOIN?
SELECT *FROM students aJOIN grades bON /* What goes here? ⁉ */;A hash join is possible with an equality (=) condition in the ON clause.
=is the key predicate shape for hash joins>and>=are not hash-join predicatesHASH JOINis not a valid syntax in PostgreSQL
The planner may still choose a nested loop or merge join depending on table size, statistics, indexes, and memory settings.
Which is correct for case-sensitive column names?
CREATE TABLE grades ( "Student Name" VARCHAR(100), 'Student Grade' INTEGER);In PostgreSQL:
- Double quotes (
") are for identifiers (table names, column names) - Single quotes (
') are for string literals
Best practices:
- Avoid mixed case or spaces in names
- Use snake_case for identifiers
- Only use quoted identifiers when absolutely necessary
How do you specify a column name containing a period?
CREATE TABLE teachers ( id INT GENERATED BY DEFAULT AS IDENTITY, first.name TEXT, -- How do you include the column: first.name? salary NUMERIC);PostgreSQL uses double quotes for identifier quoting:
- Double quotes
"..."for identifiers (column names, table names) - Single quotes
'...'for string literals - The form
first.nameis interpreted astable_name.column_name
Without quotes, a period in a column name would be interpreted as a schema/table separator! Additionally, all unquoted identifiers are lower-cased by default.
In order to reduce surprises, it’s best to use snake_case and avoid using special characters.
Which is valid syntax to randomly sample 10% of students?
This one is tricky! It features roughly 6 traps, some include:
- High level description + fragments of syntax. Tests how you adapt & assemble incomplete info.
- Requires familiar knowledge of
TABLESAMPLEsyntax, since none of theTABLESAMPLEoptions use the correct syntax! (Sinister! I know! Keep going, I believe in you!!! ❤️) - The
ROW_NUMBER() OVER (ORDER BY RAND())andORDER BY RANDOM() > 10are more red herrings. They look like they could be correct, but they’re not.RAND()isn’t a thing. AndRANDOM() > 10is a boolean expression that will always be false sinceRANDOM()always is in the range0.0-1.0. One more problem, theORDER BY RANDOM() > 10would also sort on a boolean value, not a random number. But that> 10sure felt like it could be a percentage, right? BERNOULLIis valid, howeverSAMPLETABLEis not.WHERE RANDOM() >= 0.1is a trick!RANDOM()returns a value in the range0.0 <= x < 1.0, so>= 0.1would return about 90% of the rows, not 10%.
As for the TABLESAMPLE method, PostgreSQL supports two sampling methods:
BERNOULLI: Each row has equal probabilitySYSTEM: Block-level sampling (faster but less random)
To learn more about sampling, check out this article from Render.
Example:
-- Sample 10% of rowsSELECT * FROM students TABLESAMPLE BERNOULLI (10);
-- For repeatable results, use REPEATABLE:SELECT * FROM studentsTABLESAMPLE BERNOULLI (10) REPEATABLE (42);Also worth mentioning, TABLESAMPLE has been reported to not be very random. If you need a more random fixed-size sample, consider using ORDER BY RANDOM() LIMIT 10. But be aware that this returns 10 rows, not 10%, and can be slow on large tables.
There are also some third-party extensions that provide better random sampling methods, but that’s out of scope for this! 😅
What does this incantation do?
CREATE INDEX idx_active_studentsON students(last_name)WHERE status = 'active';This trick is called a Partial Index.
They are useful for reducing disk use & speeding queries when only a subset of rows are typically queried.
The planner can consider this index when it can prove that the query conditions imply status = 'active'. Exact textual matching is not always necessary, but the planner’s implication checks are limited; a parameterized condition may not establish the predicate at planning time. Eligibility does not guarantee that the index is chosen.
Reminder: Postgres doesn’t support ‘query hints’ like other RDBMSs. The query planner will decide when to use any appropriate index(es).
What does EXPLAIN ANALYZE do for UPDATE statements?
EXPLAIN ANALYZEUPDATE studentsSET grade = grade + 1WHERE status = 'active';EXPLAIN ANALYZE actually executes the query! Be careful analyzing a write operation, specifically UPDATE, DELETE, and INSERT statements. You may have to run cleanup operations after each EXPLAIN ANALYZE to get repeatable results.
Best practices:
- Use
EXPLAIN(without ANALYZE) for UPDATE/DELETE/INSERT - Wrap modifications in transactions:
BEGIN;EXPLAIN ANALYZE ...;ROLLBACK;Well done! You went deep on several areas of PostgreSQL! 🐘
I hope you learned something new, or at least got a score to gloat about! 🏆
Want more thrills in life? Check out my Quiz Collection for endless* fun!
