Blog
In-depth articles about SQL, common mistakes, and techniques worth learning.
NULL Handling
Why Does NULL Break Your WHERE Clause in SQL?
WHERE silently drops NULL rows because comparisons with NULL are unknown, not false. See the NOT IN query that returns zero rows for everyone.
Window Functions
How Do You Calculate a Running Total in SQL?
Build a running total with SUM() OVER, then fix the bug where two orders placed on the same date silently share one total.
Joins
INNER JOIN vs LEFT JOIN in SQL, With Real Output
See exactly which rows each join keeps, why switching between them sometimes changes nothing, and the row-count bug neither tutorial warns you about.
Window Functions
How Do You Find and Delete Duplicate Rows in SQL?
Find duplicate rows with GROUP BY, preview exactly what a delete will remove with ROW_NUMBER, and avoid the NULL and engine gotchas that break both.
Aggregation
ROUND(AVG(x)) vs AVG(ROUND(x)) in SQL
Rounding a column before you average it and rounding the average itself are different calculations in SQL, and the gap grows with every tie.
Window Functions
RANK vs DENSE_RANK vs ROW_NUMBER in SQL
RANK and DENSE_RANK can let more rows through a top-N filter than you asked for. See the tie that breaks WHERE rnk <= 3 and how to fix it.
Aggregation
Why Averaging Your Averages Gives the Wrong Number in SQL
AVG(AVG(x)) is not the same as AVG(x) unless every group has the same row count. See the query that proves it and the weighted-average fix.
Aggregation
How Do You Find the Second Highest Salary in SQL?
Compare the MAX subquery, LIMIT OFFSET, and DENSE_RANK approaches, and see why each one returns something different when there's a tie or no runner-up.
CTE
When Should You Use a CTE Instead of a Subquery?
Correlation is the real dividing line between a CTE and a subquery, not readability, and the "CTEs always run once" claim is not a language rule.
Aggregation
Why COUNT(*) and COUNT(column) Give Different Answers in SQL
COUNT(*), COUNT(column), and AVG() each follow a different rule for NULLs, so mixing them in one query can quietly produce the wrong number.
String Functions
REPLACE in SQL Is Two Different Things
REPLACE() rewrites text inside a string. REPLACE INTO rewrites a whole row. They share a keyword and nothing else, and mixing them up breaks queries.
Aggregation
Where vs Having in SQL
WHERE and HAVING filter different sets of rows, so moving a condition between them can change your numbers, not just your syntax.
GROUP BY
Why SQL Says a Column Must Appear in the GROUP BY Clause
Fix the GROUP BY "column must appear" error, understand why it fires, and see why MySQL's silent version of the same bug is worse than an error.
Date Functions
Why DATEDIFF Gives the Wrong Age in SQL
DATEDIFF counts calendar boundaries crossed, not elapsed time. See the exact bug that inflates age and tenure, and the one-line fix.
Window Functions
Window Functions Explained by Example
Ranking, running totals and month-over-month change, built one clause at a time, plus the frame default that quietly breaks running totals on ties.
Performance
How to Actually Read a Query Plan
A practical guide to reading execution plans inside out, comparing estimated rows against actual rows, and fixing the one operator that matters.
SQL Basics
Six SQL Mistakes Beginners Make
The six bugs that bite almost every new SQL writer (NULL comparisons, filtered LEFT JOINs, WHERE versus HAVING) and how to catch each one yourself.