Skip to content

Quick-reference cheat sheet

Chapter 25 4 code blocks 2638 words

The code in this chapter uses these filesrun it on your own machine

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

The order you write vs the order it runsWRITE: SELECT → FROM → WHERE → GROUP BY → HAVING → ORDER BY → LIMIT RUN: FROM/JOIN → WHERE → GROUP BY → HAVING → SELECT → DISTINCT → ORDER BY → LIMIT ↑ aliases are born here
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

python48 lines
-- 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?

Decide in three questions
  1. How many variables? 1 → distribution 2 → relationship 3+ → facet or grid
  2. What types are they? numeric / categorical / time
  3. 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

Axes-level → figure-levelscatterplot, lineplot → relplot histplot, kdeplot, ecdfplot, rugplot → displot barplot, countplot, boxplot, violinplot, boxenplot, stripplot, swarmplot, pointplot → catplot regplot, residplot → lmplot axes-level : takes ax=, returns Axes, size via plt.figure(figsize=) figure-level: no ax=, returns Grid, size via height= and aspect=, supports col= / row=, title via g.figure.suptitle()
python43 lines
# 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

python24 lines
# 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

python8 lines
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

From question to chart1. QUESTION Say it in one sentence. Name the output: how many rows, which columns. 2. SQL FROM → JOIN → WHERE → GROUP BY → SELECT Build it in layers, running each layer. Check COUNT(*) before and after every JOIN. ← fan-out Reduce here: filter, aggregate, select only what you need. 3. PANDAS pd.read_sql(q, conn, params=(...), parse_dates=[...]) df.info() ← the single most valuable call Fix dtypes. Count NaN. Decide, do not reflex-drop. 4. EDA shape → missing → 1 var → 2 vars → many vars → outliers Always colour by the obvious group. ← Simpson's paradox 5. CHART sns.set_theme(style="whitegrid", context="talk") Pick from the plot-picker table. Two or three variables, max. Label axes in human words, not column names. 6. SAVE plt.savefig(..., dpi=300, bbox_inches="tight") BEFORE plt.show() 7. WRITE The deliverable is 3-5 sentences of findings, not 20 charts. Report n. Report what you excluded and why.
💡 The three sentences to memorise
  1. SQL does not run in the order you write it — FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY.
  2. NULL means unknown, so every comparison with it is UNKNOWN and WHERE keeps only TRUE.
  3. 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.

Write on Telegram Contents