Quick-reference cheat sheet
Everything in the guide, compressed. This chapter is meant to be printed — use the PDF button and export chapter 25 alone. Nothing here is explained; every item links back to the chapter that explains it.
SQL — core syntax
| Task | Syntax | Ch. |
|---|---|---|
| Pick columns | SELECT a, b AS label FROM t |
2 |
| Filter rows | WHERE x > 5 AND (y = 'a' OR z IS NULL) |
2 |
| Sort | ORDER BY a DESC, b ASC |
2 |
| Limit / paginate | LIMIT 10 OFFSET 20 |
2 |
| Unique rows | SELECT DISTINCT a, b |
2 |
| List membership | WHERE city IN ('A','B') |
3 |
| Range (inclusive) | WHERE g BETWEEN 80 AND 90 |
3 |
| Text pattern | WHERE name LIKE 'Kar%' · %=many, _=one |
3 |
| Missing values | WHERE g IS NULL / IS NOT NULL |
1, 3 |
| Replace NULL | COALESCE(a, b, 'default') |
3 |
| Guard division | x / NULLIF(y, 0) |
3 |
| Aggregate | COUNT/SUM/AVG/MIN/MAX |
4 |
| Group | GROUP BY a HAVING COUNT(*) > 1 |
4 |
| Join | JOIN t2 ON t1.id = t2.id |
5 |
| Keep unmatched | LEFT JOIN t2 ON ... |
5 |
| Named step | WITH s AS (SELECT ...) SELECT ... FROM s |
6 |
| Existence test | WHERE EXISTS (SELECT 1 FROM ...) |
6 |
| Rank | ROW_NUMBER() OVER (PARTITION BY g ORDER BY x DESC) |
7 |
| Previous row | LAG(x) OVER (ORDER BY d) |
7 |
| Running total | SUM(x) OVER (ORDER BY d) |
7 |
| If/else | CASE WHEN c THEN a ELSE b END |
8 |
| Stack results | UNION ALL |
9 |
| In both / only first | INTERSECT / EXCEPT |
9 |
| Speed up a filter | CREATE INDEX i ON t(col) |
11 |
| See the plan | EXPLAIN QUERY PLAN <query> |
11 |
SQL — the patterns worth memorising
-- Top N per group ................................................ Ch.7 WITH r AS (SELECT *, ROW_NUMBER() OVER (PARTITION BY g ORDER BY x DESC) rn FROM t) SELECT * FROM r WHERE rn <= 3; -- Which X has no Y? (anti-join) ................................. Ch.5 SELECT a.* FROM a LEFT JOIN b ON a.id = b.a_id WHERE b.a_id IS NULL; -- NULL-safe alternative: SELECT * FROM a WHERE NOT EXISTS (SELECT 1 FROM b WHERE b.a_id = a.id); -- Find duplicates ................................................ Ch.4 SELECT k1, k2, COUNT(*) FROM t GROUP BY k1, k2 HAVING COUNT(*) > 1; -- Pivot: rows to columns ......................................... Ch.8 SELECT g, SUM(CASE WHEN s = 'a' THEN 1 ELSE 0 END) AS a, SUM(CASE WHEN s = 'b' THEN 1 ELSE 0 END) AS b FROM t GROUP BY g; -- Percentage of a group matching a condition ..................... Ch.4 ROUND(100.0 * SUM(CASE WHEN cond THEN 1 ELSE 0 END) / COUNT(*), 1) -- Each row's share of the total .................................. Ch.7 ROUND(100.0 * COUNT(*) / SUM(COUNT(*)) OVER (), 1) -- Month-over-month change ........................................ Ch.7 (n - LAG(n) OVER (ORDER BY m)) * 100.0 / LAG(n) OVER (ORDER BY m) -- Second / Nth highest ........................................... Ch.13 WITH r AS (SELECT x, DENSE_RANK() OVER (ORDER BY x DESC) k FROM t) SELECT DISTINCT x FROM r WHERE k = 2; -- Median (no MEDIAN() in standard SQL) ........................... Ch.13 WITH o AS (SELECT x, ROW_NUMBER() OVER (ORDER BY x) rn, COUNT(*) OVER () n FROM t) SELECT AVG(x) FROM o WHERE rn IN ((n+1)/2, (n+2)/2); -- Safe date range (never BETWEEN on a timestamp) ................. Ch.3 WHERE d >= '2026-01-01' AND d < '2026-02-01'; -- Aggregate BEFORE joining, to avoid fan-out ..................... Ch.5 WITH per AS (SELECT fk, COUNT(*) n FROM child GROUP BY fk) SELECT p.*, per.n FROM parent p LEFT JOIN per ON per.fk = p.id; -- Safe update ritual ............................................. Ch.10 SELECT * FROM t WHERE cond; -- 1. look BEGIN TRANSACTION; -- 2. protect UPDATE t SET c = v WHERE cond; -- 3. same WHERE SELECT * FROM t WHERE cond; -- 4. check COMMIT; -- or ROLLBACK
SQL — gotchas in one line each
GotchaFixCh.
NOT IN + a NULL → zero rows, no errorNOT EXISTS3
COUNT(*) after LEFT JOIN → 0 becomes 1COUNT(right.pk)5
Join to the many side inflates SUMAggregate first, then join5
Right-table filter in WHERE kills the LEFT JOINPut it in ON5
col <> 'x' drops NULL rows silentlyOR col IS NULL2
12/20*100 = 0* 100.02
CASE without a NULL branch → ungraded reads as FWHEN x IS NULL first8
GROUP BY hides empty groupsLEFT JOIN from the dimension4, 5
SUM over zero rows = NULLCOALESCE(SUM(x),0)4
ELSE 0 inside AVG(CASE...)Omit the ELSE8
LIMIT with no ORDER BYAlways sort first2
Alias used in WHERERepeat it, or use a CTE2
Window function in WHERECTE, then filter7
Function wrapped round a filtered columnRewrite as a range11
UPDATE/DELETE with no WHERE``SELECT first, in a transaction10
SQLite ignores foreign keys by defaultPRAGMA foreign_keys = ON10
f-string SQL in PythonParameters ?12
Missing conn.commit()``with conn:12
Which plot do I need?
- How many variables? 1 → distribution 2 → relationship 3+ → facet or grid
- What types are they? numeric / categorical / time
- How many rows? small → show points large → show density
| Question | Data | Plot | Ch. |
|---|---|---|---|
| How is it spread? | 1 numeric | histplot, kdeplot, ecdfplot |
16 |
| How many of each? | 1 categorical | countplot |
17 |
| Do they move together? | 2 numeric | scatterplot, jointplot |
15, 20 |
| Is there a trend? | 2 numeric | regplot, lmplot |
19 |
| Over time? | time + numeric | lineplot |
15 |
| Different between groups? | cat + numeric | boxplot, violinplot |
17 |
| Average per group? | cat + numeric | barplot (a mean!) |
17 |
| Two categories interacting? | 2 categorical | heatmap of crosstab |
18 |
| What relates to what? | many numeric | corr heatmap, pairplot |
18, 20 |
| Holds in every subgroup? | any + category | col= faceting |
20 |
| Where are the extremes? | 1 numeric | boxplot |
17 |
| Too many points to see | 2 numeric, large n | hexbin, 2D histplot, kdeplot |
16, 20 |
Seaborn — function reference
# the shape every seaborn call takes sns.PLOT(data=df, x="col", y="col", hue="col", ...) # relational .................................................. Ch.15 sns.scatterplot(data=d, x=, y=, hue=, size=, style=, alpha=) sns.lineplot(data=d, x=, y=, hue=, errorbar=("ci", 95)) sns.relplot(data=d, x=, y=, col=, row=, kind="scatter"|"line", height=, aspect=) # distribution ................................................ Ch.16 sns.histplot(data=d, x=, bins=|binwidth=, stat="count"|"density", kde=True, hue=, multiple="layer"|"dodge"|"stack"|"fill", element="bars"|"step") sns.kdeplot(data=d, x=, y=, bw_adjust=1, fill=True, cut=0, common_norm=False) sns.ecdfplot(data=d, x=, hue=) sns.displot(data=d, x=, col=, kind="hist"|"kde"|"ecdf") # categorical ................................................. Ch.17 sns.countplot(data=d, x=, hue=) # counts ROWS sns.barplot(data=d, x=, y=, estimator="mean", errorbar=("ci",95)) # a MEAN sns.boxplot(data=d, x=, y=, hue=, order=[...]) sns.violinplot(data=d, x=, y=, hue=, split=True, cut=0, inner="box") sns.stripplot(data=d, x=, y=, jitter=.25, alpha=.6) # small n sns.swarmplot(data=d, x=, y=, size=3) # small n only sns.pointplot(data=d, x=, y=, hue=) sns.catplot(data=d, x=, y=, col=, kind="box"|"bar"|"violin"|"strip"|"count") # matrix (WIDE data) .......................................... Ch.18 sns.heatmap(matrix, annot=True, fmt=".2f", cmap="coolwarm", center=0, vmin=-1, vmax=1, mask=mask, linewidths=.5) sns.clustermap(matrix, cmap="vlag", center=0) # get a matrix first: df.pivot(index=, columns=, values=) | df.pivot_table(...) | pd.crosstab(a, b) df.corr(numeric_only=True) # pandas 2+ needs this # regression .................................................. Ch.19 sns.regplot(data=d, x=, y=, order=2, lowess=True, robust=True, logistic=True, ci=95) sns.residplot(data=d, x=, y=) sns.lmplot(data=d, x=, y=, hue=, col=, height=, aspect=) # grids ....................................................... Ch.20 sns.pairplot(d, hue=, vars=[...], diag_kind="kde", corner=True, kind="scatter") sns.jointplot(data=d, x=, y=, kind="scatter"|"hex"|"kde"|"reg", height=) g = sns.FacetGrid(d, col=, row=, col_wrap=3, height=, hue=) g.map_dataframe(sns.scatterplot, x=, y=); g.add_legend()
Seaborn — styling and output
# theme ....................................................... Ch.21 sns.set_theme(style="whitegrid", context="talk", palette="deep", font_scale=1.1) # style: darkgrid | whitegrid | dark | white | ticks # context: paper | notebook | talk | poster (scales ink, NOT figure size) sns.despine() # palettes — match the palette TYPE to the data type qualitative : "deep" "muted" "colorblind" "Set2" # unordered categories sequential : "viridis" "rocket" "mako" "Blues" # low → high diverging : "coolwarm" "vlag" "RdBu_r" # midpoint — use center=0 # finishing (matplotlib) plt.figure(figsize=(9, 5)) # axes-level only plt.title("...") ; plt.xlabel("...") ; plt.ylabel("...") plt.xticks(rotation=45, ha="right") plt.legend(title="", bbox_to_anchor=(1.02, 1), loc="upper left") plt.axhline(0, ls="--", color="grey") ax.bar_label(ax.containers[0], fmt="%.0f") plt.tight_layout() # save — ALWAYS before plt.show() plt.savefig("f.png", dpi=300, bbox_inches="tight") # 300 print, 100 screen g.savefig("f.png", dpi=300, bbox_inches="tight") # figure-level plt.show()
SQL ↔ pandas ↔ seaborn
import sqlite3, pandas as pd, numpy as np, seaborn as sns, matplotlib.pyplot as plt conn = sqlite3.connect("school.db") df = pd.read_sql("SELECT ... FROM ... WHERE ...", conn, params=(value,), # NEVER an f-string parse_dates=["enrolled_at"]) conn.close() sns.boxplot(data=df, x="course", y="grade")
Seaborn — gotchas in one line each
GotchaFixCh.
barplot shows a mean, not a countcountplot counts rows17
plt.title() titles only the last facetg.figure.suptitle()20
figsize ignored by figure-levelheight=, aspect=20
savefig after show → blank fileSave first21
KDE invents density past the datacut=0, or use histplot16
Bin count changes the storyTry several; prefer binwidth16
Boxplot hides bimodalityviolinplot17
swarmplot drops points on large nstripplot or violinplot17
Alphabetical category order is meaninglessorder=[...]17
df.corr() errors on text columnsnumeric_only=True18
Diverging colormap without a midpointcenter=0, vmin/vmax18
CI band read as a prediction intervalIt is uncertainty of the line19
lmplot rejects ax=Use regplot19
pairplot drops NaN rows silentlyCheck isna() first20
Sequential palette on unordered categoriesUse a qualitative palette21
Colour as the only encodingAdd marker/linestyle/labels21
load_dataset() needs internetSave CSVs beforehand14
Wide data into a long-format functiondf.melt()14
Long data into heatmap``df.pivot()18
distplot / ci=``histplot / errorbar=14
The one-page workflow
- SQL does not run in the order you write it — FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
- NULL means unknown, so every comparison with it is UNKNOWN and
WHEREkeeps only TRUE. - Reduce in SQL, analyse in Python, and plot only what you can explain in a sentence.
Questions about this chapter?
The course, homework review and the other five books are in Uzbek. Questions in English are welcome on Telegram.