Master the SQL that interviews actually test
A LeetCode-style gym of 101+ problems spanning every corner of SQL — joins, aggregation, subqueries, set ops, CTEs & recursion, window functions, ranking, pivoting, dates, strings and NULL logic. Every query runs live in your browser on a real SQLite engine, and each ships a worked solution with a step-by-step explanation.
101 problems
| # | Title | Category | Difficulty |
|---|---|---|---|
| 1 | Generate a Number Sequence WITH RECURSIVEanchor + recursive memberRecursive CTEs | Recursive CTEs | Easy |
| 2 | Running Total of Sales SUM() OVERORDER BY frameWindow Functions | Window Functions | Easy |
| 3 | Above-Average Spenders multiple CTEsaggregate then compareCTEs | CTEs | Medium |
| 4 | Second Highest Salary (DENSE_RANK) DENSE_RANKfilter on rankRanking | Ranking | Medium |
| 5 | Customers Who Bought Every Product relational divisionCOUNT(DISTINCT)HAVINGAdvanced Filtering | Advanced Filtering | Hard |
| 6 | Custom Priority Sort CASE in ORDER BYcustom collation orderOrdering | Ordering | Medium |
| 7 | Employee Hierarchy Levels WITH RECURSIVEhierarchylevel counterRecursive CTEs | Recursive CTEs | Medium |
| 8 | 3-Day Moving Average AVG() OVERROWS BETWEEN frameWindow Functions | Window Functions | Medium |
| 9 | Filter, Then Compare Within a CTE CTE filteringself-reference for aggregateCTEs | CTEs | Medium |
| 10 | Top 2 Products per Category ROW_NUMBERPARTITION BYtop-N-per-groupRanking | Ranking | Medium |
| 11 | Find Duplicate Emails GROUP BYHAVING COUNTAdvanced Filtering | Advanced Filtering | Easy |
| 12 | Sort With NULLs Last NULL orderingexpression sort keyOrdering | Ordering | Medium |
| 13 | Build the Org Path WITH RECURSIVEstring accumulationpathRecursive CTEs | Recursive CTEs | Medium |
| 14 | Month-over-Month Change LAG()previous-row accessWindow Functions | Window Functions | Medium |
| 15 | Category Revenue Leaders chained CTEsjoin CTE to CTEratio thresholdCTEs | CTEs | Hard |
| 16 | RANK vs DENSE_RANK RANKDENSE_RANKtie handlingRanking | Ranking | Easy |
| 17 | Second Highest, No LIMIT correlated subqueryMAX of a filtered setAdvanced Filtering | Advanced Filtering | Medium |
| 18 | Order by Best Value computed sort keyCASTalias in ORDER BYOrdering | Ordering | Easy |
| 19 | Fill the Date Gaps WITH RECURSIVEcalendar generationLEFT JOINRecursive CTEs | Recursive CTEs | Hard |
| 20 | Percent of Category Total SUM() OVER PARTITION BYratio to group totalWindow Functions | Window Functions | Medium |
| 21 | Highest and Lowest Earner ORDER BY + LIMIT inside a CTEUNION ALLfinal orderingCTEs | CTEs | Medium |
| 22 | Consecutive Login Streaks (Gaps & Islands) ROW_NUMBERgaps and islandsgrouping trickRanking | Ranking | Hard |
| 23 | Customers With No Orders anti-joinNOT EXISTSAdvanced Filtering | Advanced Filtering | Easy |
| 24 | Multi-Key Ordering multiple sort keysmixed ASC/DESCOrdering | Ordering | Easy |
| 25 | Fibonacci Sequence WITH RECURSIVEcarried statemultiple accumulatorsRecursive CTEs | Recursive CTEs | Medium |
| 26 | First and Last Close per Symbol FIRST_VALUELAST_VALUEexplicit frame gotchaWindow Functions | Window Functions | Hard |
| 27 | Score Quartiles with NTILE NTILEbucketingRanking | Ranking | Medium |
| 28 | Departments Above Average Headcount aggregate of aggregatessubquery in WHEREAdvanced Filtering | Advanced Filtering | Medium |
| 29 | Difference From Subject Average AVG() OVER PARTITION BYrow vs group comparisonWindow Functions | Window Functions | Medium |
| 30 | Employee and Their Manager INNER JOINself-joinJoins | Joins | Easy |
| 31 | Every Product and Units Sold LEFT JOINCOALESCEGROUP BYJoins | Joins | Easy |
| 32 | Headcount per Department INNER JOINGROUP BYCOUNTJoins | Joins | Easy |
| 33 | Assign Letter Grades (Band Join) non-equi joinBETWEENrange lookupJoins | Joins | Medium |
| 34 | Customers Who Placed Orders semi-joinEXISTSINJoins | Joins | Medium |
| 35 | Customers Without Orders anti-joinNOT EXISTSLEFT JOIN ... IS NULLJoins | Joins | Medium |
| 36 | Size × Color Product Matrix CROSS JOINCartesian productJoins | Joins | Medium |
| 37 | Warmer Than the Previous Day self-joinnon-equi joindate arithmeticJoins | Joins | Medium |
| 38 | All Students and All Memberships FULL OUTER JOINNULLS LASTunmatched rowsJoins | Joins | Hard |
| 39 | Coworker Pairs in the Same Department self-joinpair generationdeduplicate A-B/B-AJoins | Joins | Hard |
| 40 | Spend per Customer Across Three Tables three-table joinGROUP BYSUMJoins | Joins | Hard |
| 41 | Distinct Products Per Store COUNT(DISTINCT)GROUP BYAggregation | Aggregation | Easy |
| 42 | Orders Per Customer GROUP BYCOUNTAggregation | Aggregation | Easy |
| 43 | Revenue By Category GROUP BYSUMAVGAggregation | Aggregation | Easy |
| 44 | Big Spenders (HAVING Threshold) GROUP BYHAVINGSUMAggregation | Aggregation | Medium |
| 45 | Grade Distribution By Class GROUP BY multiple columnsCOUNTAggregation | Aggregation | Medium |
| 46 | Paid vs Unpaid Invoices conditional aggregationCASEFILTERAggregation | Aggregation | Medium |
| 47 | Pass Rate Per Quiz ratio of subgroup to totalconditional aggregationAVGAggregation | Aggregation | Medium |
| 48 | Tags Per Post (Ordered List) group_concatordered aggregationGROUP BYAggregation | Aggregation | Medium |
| 49 | Department Payroll (Aggregate Over Join) aggregate over joinJOINGROUP BYAggregation | Aggregation | Hard |
| 50 | Favorite Genre Per User (Mode) modemost-frequent valueCOUNTAggregation | Aggregation | Hard |
| 51 | Weighted Course GPA weighted averageSUMROUNDAggregation | Aggregation | Hard |
| 52 | Order Count Per Customer (Scalar Subquery) scalar subquerysubquery in SELECTcorrelated subquerySubqueries | Subqueries | Easy |
| 53 | Orders Above the Overall Average comparison to scalar subqueryAVGsubquery in WHERESubqueries | Subqueries | Easy |
| 54 | Books by Prolific Authors (Uncorrelated Subquery Filter) uncorrelated subqueryINGROUP BYSubqueries | Subqueries | Medium |
| 55 | Customers With a Big Order (IN vs EXISTS) INEXISTSsemi-joinSubqueries | Subqueries | Medium |
| 56 | Products Priced Above Their Category Average correlated subquerysubquery in WHEREAVGSubqueries | Subqueries | Medium |
| 57 | Top Spenders via a Derived Table derived tablesubquery in FROMGROUP BYSubqueries | Subqueries | Medium |
| 58 | Departments Beating the Company Average (HAVING + Subquery) subquery in HAVINGAVGGROUP BYSubqueries | Subqueries | Hard |
| 59 | Each Customer's Most Expensive Order greatest-n-per-groupcorrelated subqueryMAXSubqueries | Subqueries | Hard |
| 60 | All People Across Two Tables (UNION dedupe) UNIONdeduplicationORDER BYSet Operations | Set Operations | Easy |
| 61 | Customers Who Bought on Both Channels (INTERSECT) INTERSECTdeduplicationORDER BYSet Operations | Set Operations | Easy |
| 62 | Churned Customers (EXCEPT) EXCEPTanti-joindeduplicationSet Operations | Set Operations | Medium |
| 63 | UNION ALL vs UNION: Counting Logins UNION ALLUNIONduplicatesSet Operations | Set Operations | Medium |
| 64 | Items on Exactly One Menu (Symmetric Difference) symmetric differenceEXCEPTUNIONSet Operations | Set Operations | Hard |
| 65 | Signup Funnel Conversion CTE chainingFunnelConversion rateCTEs | CTEs | Medium |
| 66 | Everyone Who Reports Up To A Manager Recursive CTETransitive ClosureGraphRecursive CTEs | Recursive CTEs | Hard |
| 67 | Split CSV Tags Into Rows Recursive CTEString SplitSUBSTRRecursive CTEs | Recursive CTEs | Hard |
| 68 | Exam Score Percentile CUME_DISTPERCENT_RANKWindow FunctionsWindow Functions | Window Functions | Medium |
| 69 | Gap To Next Login LEADWindow FunctionsDate DiffWindow Functions | Window Functions | Medium |
| 70 | Running Maximum Balance MAX OVERRunning AggregateWindow FunctionsWindow Functions | Window Functions | Medium |
| 71 | Daily Cumulative Sales (RANGE vs ROWS) RANGE frameROWS frameWindow FunctionsWindow Functions | Window Functions | Hard |
| 72 | Deduplicate Keeping Latest Contact ROW_NUMBERDeduplicationRankingRanking | Ranking | Medium |
| 73 | Top Scorers With Ties RANKTop-N with tiesRankingRanking | Ranking | Medium |
| 74 | Median Home Price ROW_NUMBERMedianRankingRanking | Ranking | Hard |
| 75 | Pivot Order Status Counts conditional aggregationCOUNTSUMPivoting | Pivoting | Medium |
| 76 | Pivot Quarterly Sales into Columns conditional aggregationSUMCASEPivoting | Pivoting | Medium |
| 77 | Unpivot Subject Scores into Rows UNION ALLunpivotPivoting | Pivoting | Medium |
| 78 | Binary Skill Presence Matrix conditional aggregationMAXCASEPivoting | Pivoting | Hard |
| 79 | Pivot Months then Add a Total conditional aggregationSUMderived columnPivoting | Pivoting | Hard |
| 80 | Two-Dimensional Pivot: Store by Quarter conditional aggregationtwo-dimensional pivotSUMPivoting | Pivoting | Hard |
| 81 | Days Between Subscription Dates juliandayDates & Time | Dates & Time | Easy |
| 82 | Extract Year, Month, and Weekday strftimeDates & Time | Dates & Time | Easy |
| 83 | Weekend Events Only strftimeweekday filterDates & Time | Dates & Time | Easy |
| 84 | Age in Whole Years strftimewhole-year ageDates & Time | Dates & Time | Medium |
| 85 | Count Events Per Month strftimeGROUP BY monthDates & Time | Dates & Time | Medium |
| 86 | First and Last Day of Each Month date modifiersstart of monthDates & Time | Dates & Time | Medium |
| 87 | Orders in the Last 30 Days date arithmeticreference dateDates & Time | Dates & Time | Medium |
| 88 | Events Per Weekday Name strftimeweekday mappingGROUP BYDates & Time | Dates & Time | Hard |
| 89 | Build a Full Name concatenation||String Manipulation | String Manipulation | Easy |
| 90 | Case-Insensitive Product Search lowerLIKEString Manipulation | String Manipulation | Easy |
| 91 | Clean Phone Numbers with replace replaceString Manipulation | String Manipulation | Easy |
| 92 | Count Items in a CSV Field lengthreplaceString Manipulation | String Manipulation | Medium |
| 93 | Extract the Email Domain substrinstrString Manipulation | String Manipulation | Medium |
| 94 | Format Prices with printf printfString Manipulation | String Manipulation | Medium |
| 95 | Avoid Divide-by-Zero with NULLIF NULLIFCOALESCENULL Handling | NULL Handling | Easy |
| 96 | Default Missing Values with COALESCE COALESCEIFNULLNULL Handling | NULL Handling | Easy |
| 97 | COUNT(*) vs COUNT(column) and AVG over NULLs COUNT(*)COUNT(col)AVG ignores NULLNULL Handling | NULL Handling | Medium |
| 98 | IS NULL, IS NOT NULL, and Three-Valued Logic IS NULLIS NOT NULLthree-valued logicNULL Handling | NULL Handling | Medium |
| 99 | The NOT IN NULL Trap NOT EXISTSNOT IN pitfallthree-valued logicNULL Handling | NULL Handling | Hard |
| 100 | Bought Product X But Not Product Y EXISTSNOT EXISTSAnti-joinAdvanced Filtering | Advanced Filtering | Medium |
| 101 | Case-Insensitive Name Sort COLLATE NOCASEgroup_concatDeterministic orderOrdering | Ordering | Medium |