PyCodeItPython trace & interview prep
DashboardMastery MapSQL PracticeDailyInterviewCompaniesBlogLeaderboardCommunity
Next-Gen Developer Practice Sandbox

Predict output. Query databases.
Pass technical interviews.

Two full practice tracks in one place. Trace Python execution line by line, or write and verify SQL queries against live database tables, all running directly in your browser with no installation required.

Python Sandbox

Syntax Tracing & Logic

Analyze and dry-run decorators, mutable defaults, variable scopes, closures, and loops to predict console stdout.

100+ challenges

SQL Playground

WASM SQLite Engine

Write queries and check executions against HR, E-Commerce, and Competition database tables in real-time.

200+ queries

Interactive Curriculum

Practice Python tracing and SQL queries in one place.

Read the learning blog →

In-Browser Sandbox

Run Python trace problems and SQL queries without installing anything. The Python track uses a frame-by-frame simulator; the SQL track uses a WebAssembly SQLite engine with real HR, e-commerce, and competition table data.

AI-Powered Evaluation

Connect your own Gemini, Groq, or OpenRouter API key and get graded feedback on both Python submissions and SQL queries. Every evaluation includes a step-by-step explanation of the correct answer.

Structured Learning Paths

Follow topic-by-topic tracks for Python from basics through decorators, and SQL from SELECT fundamentals through window functions and CTEs. Earn XP, build streaks, and track your progress on the leaderboard.

Loading interactive sandbox engine...

Platform Breakdown

Python Code Tracing

Dry-running is the practice of mentally executing code line by line to predict output without a runtime. It reveals variable scope rules, mutable aliasing, and exception propagation in a way that reading alone does not.

SQL Live Playground

Write real queries against HR employee tables, e-commerce order data, and competition leaderboard schemas. Results appear instantly using an in-browser SQLite engine with no backend calls.

AI Challenge Generator

Bring your own Gemini, Groq, or OpenRouter key to generate unlimited fresh Python and SQL challenges at easy, medium, or hard difficulty with full evaluation feedback.

Private by Design

Your API keys are stored only in your browser's local storage and are never sent to PyCodeIt servers. All LLM calls go directly from your browser to the provider.


Python Practice Tracks cover 100+ structured topics from variables and loops through decorators and OOP.
SQL Practice Tracks cover 200+ queries from basic SELECT through window functions and recursive CTEs.

Interview prep guides

Learn Python Tracing & SQL Query Skills

Practical reads that sharpen code execution tracing, SQL join logic, and communication during technical assessments.

Jump to practice →
Article6 min readpython

How to Crack a Tech Interview Using a Trace Table

A step-by-step method for predicting Python output under pressure - without running code.

Concept in Simple Words: A trace table is like a developer's manual diary. It is a grid where you write down the line number, which variable is changing, and its new value. When you trace code in your head, your brain is forced to act as both the parser and the memory storage. Under interview pressure, this dual role leads to cognitive overload and simple arithmetic errors. By writing a trace table on paper, you delegate the memory storage to the paper and free your mind to focus purely on executing the logic.

Deep Walkthrough & Code: Let's trace a loop that aggregates values based on conditions. The following function filters even numbers and builds a running average.

def average_evens(numbers):
    total = 0
    count = 0
    for n in numbers:
        if n % 2 == 0:
            total += n
            count += 1
    return total / count if count > 0 else 0
Step-by-Step Dry Run: Suppose we call average_evens([3, 4, 8]). Let's draw our columns: [Line, Variable, Value, Notes].
- Line 2: total = 0
- Line 3: count = 0
- Line 4: First loop iteration, n = 3. 3 % 2 is 1 (not 0), so we skip the condition.
- Line 4: Second iteration, n = 4. 4 % 2 is 0. total becomes 4, count becomes 1.
- Line 4: Third iteration, n = 8. 8 % 2 is 0. total becomes 12 (4 + 8), count becomes 2.
- Line 8: Loop finishes. Return total / count -> 12 / 2 = 6.0.
Tracking variables this way prevents you from losing the count or total values under pressure.

Production Level Issue & Fix: In production, passing an empty list or a list of odd numbers causes a division by zero. We prevent this by checking 'if count > 0' before division. A more robust production version should also check if the input is a valid iterable of numbers to prevent TypeError: 'type mismatch' bugs.

Article5 min readpython

5 Common Python String Slicing Tricks Interviewers Love

Negative indices, step sizes, and reversals - master the patterns that show up in trace questions.

Concept in Simple Words: String slicing in Python is a shorthand way to extract substrings using the syntax s[start:stop:step]. Think of indices as pointing to the slots between characters rather than the characters themselves. Start is inclusive, stop is exclusive, and step is how many elements to jump. If step is negative, Python traverses the string from right to left.

Deep Walkthrough & Code: Interviewers love combinations of negative indexes and reverse steps. Let's look at a code snippet that filters palindromes or extracts dynamic prefixes:

def extract_sub(s):
    rev = s[::-1]        # Trick 1: Reverse the string
    last_three = s[-3:]  # Trick 2: Get last 3 characters
    skip_even = s[::2]   # Trick 3: Take every second character
    return rev, last_three, skip_even
Step-by-Step Dry Run: Let's trace extract_sub('Python'):
- s[::-1] starts at the end and steps backward: 'nohtyP'.
- s[-3:] starts at index -3 ('h') and goes to the end: 'hon'.
- s[::2] starts at 0, skipping every other character: 'P' -> 't' -> 'o' -> 'Pto'.
- Result: ('nohtyP', 'hon', 'Pto'). Notice that slicing never modifies the original string; it returns a new one.

Production Level Issue & Fix: If step is zero (e.g., s[::0]), Python raises a ValueError: 'slice step cannot be zero'. In production code, if the step parameter is calculated dynamically from user input, you must validate that it is not zero before slicing, like so: 'step = user_step if user_step != 0 else 1'.

Article5 min readpython

Why Dry-Running Beats Memorizing LeetCode Patterns

Pattern decks fail when interviewers change types, side effects, or control flow.

Concept in Simple Words: Memorizing LeetCode patterns is like learning templates. It works great until the interviewer makes a small tweak to the rules. A minor change, like using a generator instead of a list or adding mutable defaults, completely breaks memorized templates. Dry-running is the skill of executing code step-by-step in your head or on paper, allowing you to adapt to any modification.

Deep Walkthrough & Code: Let's look at how a memorized depth-first search (DFS) template can fail if the graph representation has side effects or dynamic attributes:

class Node:
    def __init__(self, val):
        self.val = val
        self.visited = False
        self.neighbors = []

def dfs(node):
    if not node: return
    node.visited = True
    for neighbor in node.neighbors:
        if not neighbor.visited:
            dfs(neighbor)

Step-by-Step Dry Run: If you dry-run this code, you notice that `node.visited` is mutated directly on the nodes. If the same graph is traversed multiple times, or in parallel, the second traversal will fail because `visited` remains `True` from the first traversal. A trace table tracking the visited state would show that nodes are never reset.

Production Level Issue & Fix: Mutating state directly on input nodes is a bad production practice. It causes race conditions in multi-threaded code. The correct fix is to use an independent `visited = set()` to track visited nodes: `if node in visited: return; visited.add(node)`.

Article6 min readpython

Reading Python List Comprehensions Line by Line

Desugar comprehensions into nested loops before you predict output.

Concept in Simple Words: List comprehensions are a clean way to build lists: [expression for item in iterable if condition]. Under the hood, Python translates this into an empty list, a loop, a conditional check, and an append operation. To trace a comprehension correctly, 'desugar' it by writing it out as a standard nested for-loop first.

Deep Walkthrough & Code: Let's look at a nested list comprehension used to flatten a matrix but filter out negative numbers:

matrix = [[1, -2], [3, 4]]
flat = [x for row in matrix for x in row if x > 0]
Step-by-Step Dry Run: Let's write out the desugared loops:
1. flat = []
2. for row in matrix:
3.     for x in row:
4.         if x > 0:
5.             flat.append(x)
Tracing row-by-row:
- Row 1: [1, -2]. x=1 is > 0 -> flat.append(1). x=-2 is not > 0 -> skip.
- Row 2: [3, 4]. x=3 is > 0 -> flat.append(3). x=4 is > 0 -> flat.append(4).
- Result: [1, 3, 4]. In Python 3, variables inside comprehensions do not leak into the enclosing scope.

Production Level Issue & Fix: Nesting comprehensions too deeply makes code unreadable and hard to debug. In production, if a list comprehension contains more than two loops or complex conditions, rewrite it as a standard generator function to save memory and make logging/debugging intermediate steps possible.

Article5 min readpython

Default Mutable Arguments: The Classic Interview Trap

Why def f(lst=[]) causes shared state - and how to spot it in a trace.

Concept in Simple Words: In Python, default argument values are evaluated once, when the function is defined, not when it is called. If you use a mutable object (like a list or dictionary) as a default argument, all function calls that do not provide an argument will share the exact same object in memory.

Deep Walkthrough & Code: Let's look at the classic buggy implementation of a list accumulator:

def append_to(element, target=[]):
    target.append(element)
    return target

print(append_to(1))
print(append_to(2))
Step-by-Step Dry Run: Let's trace this step-by-step:
- At definition time: Python creates a default list object in memory, let's call it list_ref_1 = [].
- First call: append_to(1) uses target = list_ref_1. We append 1. list_ref_1 becomes [1]. Returns [1].
- Second call: append_to(2) is called without target. It uses target = list_ref_1. We append 2. list_ref_1 becomes [1, 2]. Returns [1, 2].
This shared state leads to unexpected accumulation of values across independent function calls.
Production Level Issue & Fix: This is a major source of bugs in production APIs, where shared lists accumulate user data across requests. The fix is to use None as the default argument and instantiate the mutable object inside the function: `def append_to(element, target=None):
    if target is None:
        target = []
    target.append(element)
    return target`.
Article6 min readpython

How to Explain Your Thinking in a 45-Minute Phone Screen

Structure your narration so interviewers can follow your trace table aloud.

Concept in Simple Words: Coding interviews evaluate both your coding skills and your communication habits. Silence is a red flag. If you are solving a trace question in silence, the interviewer cannot tell if you are struggling or working. Narration turns your coding screen into a collaborative problem-solving session.

Deep Walkthrough & Code: Suppose you are asked to trace a function that checks for duplicates in a stream of data. Instead of just stating the answer, use structuring statements:

def has_duplicate(stream):
    seen = set()
    for item in stream:
        if item in seen:
            return True
        seen.add(item)
    return False

Step-by-Step Dry Run: As you trace this, say: 'First, I initialize a set called seen to keep track of historical items in O(1) average lookup time. As I iterate through the stream, I check if the current item is in seen. If it is, I return True immediately to avoid unnecessary iterations. If not, I add it to the set.'

Production Level Issue & Fix: Storing a infinite stream in a set will eventually trigger an Out Of Memory (OOM) crash in production. The fix is to use a rolling window size or a Bloom filter (for probabilistic membership) if the volume of data is too large to fit in memory.

Article6 min readpython

Recursion Trace Tables: From Base Case to Return Value

Stack frames make recursion traceable once you tabulate calls and returns.

Concept in Simple Words: Recursion is a function calling itself. Each recursive call creates a new stack frame in memory to hold local variables. To trace recursion, your table must have a column representing the stack depth. Do not mix variables from different recursive frames.

Deep Walkthrough & Code: Let's trace a recursive fibonacci function with a trace table:

def fib(n):
    if n <= 1:
        return n
    return fib(n - 1) + fib(n - 2)
Step-by-Step Dry Run: Let's trace fib(3). Our table columns are [Frame Depth, Active Call, Value of n, Returns].
- Frame 1: fib(3). n=3. n > 1, calls fib(2) + fib(1).
- Frame 2: fib(2). n=2. n > 1, calls fib(1) + fib(0).
- Frame 3: fib(1). n=1. Base case met. Returns 1 to caller (Frame 2).
- Frame 4: fib(0). n=0. Base case met. Returns 0 to caller (Frame 2).
- Frame 2: receives 1 and 0, returns 1 to caller (Frame 1).
- Frame 5: fib(1). n=1. Base case met. Returns 1 to caller (Frame 1).
- Frame 1: receives 1 (from fib(2)) and 1 (from fib(1)), returns 2.
Production Level Issue & Fix: The recursive Fibonacci function runs in O(2^n) time complexity and causes a StackOverflowError for large n. The production fix is to use memoization (cache intermediate results) or write it iteratively: `@functools.lru_cache(maxsize=None)
def fib(n):
    ...`.
Article5 min readpython

Python Dictionary Iteration Order and Pitfalls

Insertion order, views, and runtime mutations - common dry-run themes.

Concept in Simple Words: In Python 3.7+, dictionaries preserve insertion order. However, iterating over a dictionary and mutating it (adding or deleting keys) at the same time is not allowed. Python will raise an error because the dictionary size changes during iteration.

Deep Walkthrough & Code: Let's look at a function that attempts to prune a dictionary based on threshold values:

def prune_dict(d, threshold):
    for key, value in d.items():
        if value < threshold:
            del d[key]  # Bug: mutating dictionary size
    return d
Step-by-Step Dry Run: Let's trace prune_dict({'a': 1, 'b': 5}, 3):
- Loop starts iterating over d.items().
- First item: key='a', value=1. 1 < 3 is True. We delete d['a'].
- Python immediately raises a RuntimeError: 'dictionary changed size during iteration'. The iteration is interrupted.
Production Level Issue & Fix: To safely delete items during iteration in production, iterate over a copy of the keys rather than the dict views directly: `for key in list(d.keys()):
    if d[key] < threshold:
        del d[key]`.
Article6 min readsql

SQL Joins Explained for Technical Interview Candidates

Inner, left, right, and full outer joins - understand what rows survive and why before your next data round.

Concept in Simple Words: Joins combine columns from two tables based on a matching key. Think of INNER JOIN as the overlap in a Venn diagram; only rows that match on BOTH sides survive. LEFT JOIN keeps everything from the left table; if there is no match on the right, it fills the right columns with NULL. RIGHT JOIN does the opposite. FULL JOIN keeps all rows from both tables, filling mismatches on either side with NULL.

Deep Walkthrough & Code: Let's look at a LEFT JOIN comparing employee departments, and how a NULL key handles matches:

SELECT e.name, d.dept_name
FROM employees e
LEFT JOIN departments d ON e.dept_id = d.id
ORDER BY e.name;
Step-by-Step Dry Run: Suppose we have Employees: [Alice (dept_id=1), Bob (dept_id=NULL)] and Departments: [1 (Engineering)].
- Trace Alice: dept_id=1 matches Department id=1. Alice, Engineering is returned.
- Trace Bob: dept_id=NULL. NULL never equals anything, not even another NULL. LEFT JOIN preserves Bob, but department details are filled with NULL: Bob, NULL is returned.
Bob would be excluded entirely in an INNER JOIN.

Production Level Issue & Fix: A common production trap is filtering the right table columns in the WHERE clause of a LEFT JOIN: `WHERE d.dept_name = 'Engineering'`. This implicitly converts the LEFT JOIN into an INNER JOIN because rows with NULL on the right are filtered out by the WHERE condition. The fix is to place the filter condition inside the ON clause instead: `LEFT JOIN departments d ON e.dept_id = d.id AND d.dept_name = 'Engineering'`.

Article7 min readsql

Window Functions in SQL: RANK, ROW_NUMBER, and LEAD Explained

Aggregate without collapsing rows - the core skill data engineers and analysts get tested on.

Concept in Simple Words: Regular aggregate functions (like SUM or AVG) collapse multiple rows into a single summary row. Window functions perform calculations across a group of related rows, but they do NOT collapse the rows. Each row retains its individual identity while displaying the computed metric.

Deep Walkthrough & Code: Let's look at how ROW_NUMBER(), RANK(), and DENSE_RANK() assign ranking integers based on order criteria:

SELECT name, salary,
       ROW_NUMBER() OVER (ORDER BY salary DESC) as row_num,
       RANK() OVER (ORDER BY salary DESC) as rk,
       DENSE_RANK() OVER (ORDER BY salary DESC) as dense_rk
FROM employees;
Step-by-Step Dry Run: Suppose we have salaries [100k, 100k, 80k].
- Row 1 (100k): row_num = 1, rk = 1, dense_rk = 1.
- Row 2 (100k): row_num = 2 (unique index), rk = 1 (tie), dense_rk = 1 (tie).
- Row 3 (80k): row_num = 3, rk = 3 (skips 2 due to rank tie), dense_rk = 2 (next consecutive integer).
Understanding how rankings handle ties is a common interview screening question.

Production Level Issue & Fix: Running window functions without a PARTITION BY clause on tables with millions of rows forces the database to load the entire dataset into a single memory block to sort it, leading to disk-spill slowdowns. In production, always filter the dataset in a subquery or CTE first to reduce the volume of rows processed by the window function.

Article6 min readsql

CTEs vs Subqueries: When to Use Each and Why It Matters

Common Table Expressions improve readability but the performance story is more nuanced than most articles admit.

Concept in Simple Words: A subquery is a query nested inside another (e.g., in FROM or WHERE). A Common Table Expression (CTE) is defined using the `WITH` keyword at the top. Think of a CTE as a named temporary result set. It makes code readable by structuring query logic top-down, instead of nested inside-out.

Deep Walkthrough & Code: Let's look at a CTE comparing regional sales performance against a subquery equivalent:

WITH RegionalSales AS (
  SELECT region, SUM(amount) as sales
  FROM orders
  GROUP BY region
)
SELECT * FROM RegionalSales WHERE sales > 50000;

Step-by-Step Dry Run: When execution starts, the query optimizer resolves RegionalSales first: aggregating order values per region. Then, the main query executes, filtering regions with sales > 50000. It behaves like a temporary table, but only exists for the duration of the query.

Production Level Issue & Fix: In older database engines (and PostgreSQL before version 12), CTEs acted as optimization barriers, meaning the engine would materialize (compute and write to disk) the CTE completely before filtering. The production fix in older Postgres versions is to use the `NOT MATERIALIZED` hint to allow the optimizer to push filters down into the CTE for better performance: `WITH RegionalSales AS NOT MATERIALIZED (...)`.

Article6 min readsql

GROUP BY and HAVING: The Misconceptions That Cause Wrong Answers

Understanding what each clause filters and when to use WHERE versus HAVING prevents the most common SQL mistakes.

Concept in Simple Words: GROUP BY collapses multiple rows with the same value into single summary rows. The WHERE clause filters individual rows BEFORE they are grouped. The HAVING clause filters grouped summaries AFTER the grouping has occurred. You cannot reference aggregates in the WHERE clause.

Deep Walkthrough & Code: Let's look at a query designed to find departments with more than 5 employees making over 50k:

SELECT dept_id, COUNT(*)
FROM employees
WHERE salary > 50000
GROUP BY dept_id
HAVING COUNT(*) > 5;
Step-by-Step Dry Run: Order of Execution is critical:
- FROM employees: Load all employees.
- WHERE salary > 50000: Remove employees making <= 50k.
- GROUP BY dept_id: Group the remaining employees by department ID.
- COUNT(*): Count employees in each department group.
- HAVING COUNT(*) > 5: Remove department groups with 5 or fewer employees.
- SELECT: Return the resulting department IDs and headcounts.

Production Level Issue & Fix: Putting non-aggregate filters in the HAVING clause is a common production mistake (e.g. `HAVING dept_id = 3`). This forces the database to group all rows first and filter afterwards. In production, always place non-aggregate filters in the WHERE clause to minimize the row count before grouping, speeding up execution.

Article7 min readsql

What Every Developer Should Know About SQL Indexes in Interviews

B-tree indexes, composite index column order, and when a full table scan is actually faster.

Concept in Simple Words: A database index is like the index at the back of a textbook. Instead of reading the entire book page-by-page (a full table scan), you look up a keyword and jump straight to the relevant page (index scan). Indexes speed up read queries, but slow down write operations because the index must be updated on every INSERT, UPDATE, or DELETE.

Deep Walkthrough & Code: Let's look at a query filtering on user accounts and how a composite index functions:

CREATE INDEX idx_user_status_date ON users (status, created_at);
SELECT * FROM users WHERE status = 'active' AND created_at > '2026-01-01';

Step-by-Step Dry Run: Suppose we run this query on a table with 1,000,000 users. The database index is a balanced tree (B-Tree). Instead of scanning 1,000,000 rows, it searches the B-Tree for status='active', then scans the matches sorted by created_at. This reduces disk I/O operations from 1,000,000 to just a few dozen page reads.

Production Level Issue & Fix: The Left-Prefix Rule. An index on `(status, created_at)` cannot be used efficiently if the query filters ONLY on `created_at` (e.g. `WHERE created_at > '2026-01-01'`). In production, composite index columns must be ordered based on query filtering requirements, starting with the most frequently filtered, equality-constrained columns.

FAQ

Frequently Asked Questions

Everything you need to know about practicing on PyCodeIt.

Is PyCodeIt completely free?
Yes it is 100% free. You can practice Python tracing, SQL queries, and access hundreds of interview challenges without any account. Creating a free account unlocks XP tracking, daily streaks, and the leaderboard.
Do I need to install Python or any software?
No installation needed. Everything runs in your browser. The SQL engine uses WebAssembly (WASM SQLite) and Python challenges are evaluated server-side. Just open the website and start practicing immediately.
What Python topics are covered?
100+ topics: variables, loops, lists, dictionaries, functions, decorators, closures, OOP, mutable defaults, scoping, recursion, and advanced patterns, all structured the way real interviews test them.
What SQL topics are covered?
200+ exercises from basic SELECT statements through GROUP BY, JOINs, subqueries, window functions (ROW_NUMBER, RANK, LAG, LEAD), recursive CTEs, and scenario-based playbooks modelled after real company data.
How does this help me pass technical interviews?
PyCodeIt mirrors real interview formats. Python challenges train output prediction, the same mental model interviewers evaluate. SQL playbooks use real-world schemas (e-commerce, rideshare, hospital) identical to FAANG-style data engineering rounds.
Are my API keys private and secure?
Completely. Your AI provider keys (OpenAI, Groq, OpenRouter) are stored only in your browser's local storage and are never sent to PyCodeIt servers. All AI calls go directly from your browser to the provider.
Can I share or embed my coding stats?
Yes! PyCodeIt provides an embeddable profile widget. Copy the iframe code from your dashboard and paste it onto any portfolio, blog, or GitHub README. It automatically fetches your live XP, streak, accuracy, and level.

Python Practice

Cracking Technical Interviews with Programmatic Code Tracing

PyCodeIt trains you to master Python dry-runs, trace tables, and optimal coding patterns. These are the exact skills that FAANG and Tier-1 firms test during live phone screens and onsite interview loops.

What Is a Trace Table?

A trace table is a systematic grid that records how variables, references, and control flow evolve line by line as Python executes your code. Unlike rote memorization of syntax, trace-driven practice forces you to simulate the interpreter directly: stack frames, scope resolution, mutable object aliasing, generator exhaustion, and short-circuit boolean evaluation. According to the official Python execution model documentation, names in Python are resolved through a well-defined namespace hierarchy that catches most developers off guard under pressure. Interviewers at global tech firms deliberately embed subtle mutations such as nested closures, default mutable arguments, and in-place list operations to see whether candidates can predict the exact standard output without running the code.

PyCodeIt generates unique challenges using your personal API key, so every session presents fresh edge cases. You practice both dry-run trace output problems where you predict terminal output and write-optimal-code prompts aligned with real hiring bar difficulty.

Variable Scopes and the Python Memory Model

Understanding LEGB scope (Local, Enclosing, Global, Built-in) is a requirement for senior-level interview screens. When a function reads a variable, Python searches inner frames before globals. When you assign a variable without the nonlocal or global keyword, you create a new local binding. Trace tables make these rules visible: each row marks which namespace owns a name and whether a reference points to a shared heap object.

  • Stack frames push and pop on every function call
  • Immutable versus mutable types affect aliasing surprises in ways most people do not anticipate
  • Comprehensions and lambdas create hidden scopes in Python 3
  • Decorators wrap callables so you must trace both the wrapper and the wrapped function in order

Why Global Tech Firms Prioritize Dry-Running

Companies like Google, Meta, Amazon, and Stripe use dry-run questions because they reveal depth faster than trivia. The real question is whether you can reason about concurrency primitives, iterator protocols, and exception propagation under time pressure. Memorizing LeetCode patterns alone fails when interviewers swap integers for nested dicts or add a finally block that mutates shared state. PyCodeIt gamifies this skill with streaks, leaderboards, and a progressive hint system so you build genuine understanding rather than answer recognition.

The Zen of Python states that explicit is better than implicit. Trace tables are how you make the implicit behavior of your code completely explicit, which is exactly what separates passing from failing a technical screen.

Aligned with AP Computer Science Standards (USA)

Trace-based problems reinforce College Board AP Computer Science competencies including iteration, recursion, data abstraction, and algorithm analysis. Ideal for high school and early undergraduate preparation.

Start USA-aligned practice →

Silicon Valley Technical Phone Screen Preparation

Simulate Bay Area-style 45-minute screens with unpredictable Python snippets, follow-up optimizations, and the communication of your mental model out loud. Review the Tech Interview Handbook alongside your daily practice here for a complete preparation routine.

Silicon Valley dry-run drill →

UK and EU Graduate Engineering Assessment Preparation

Graduate schemes at banks, consultancies, and product companies across London, Berlin, and Dublin emphasize fundamental computer science tracing. The University of Oxford computer science curriculum covers trace-based reasoning as a core competency, and PyCodeIt maps directly to those structured assessment rubrics.

UK and EU graduate prep →

Free Python Learning Resources

PyCodeIt works best alongside structured reading. The following resources are trusted by millions of developers and pair well with daily trace practice:

  • The official Python 3 tutorial from python.org covers the language fundamentals that appear most frequently in trace problems
  • W3Schools Python reference is a quick syntax lookup used by beginners and experienced developers alike
  • Harvard CS50 Python course is completely free and builds the foundational reasoning skills that trace practice reinforces
  • GeeksforGeeks Python tutorials cover interview-specific patterns including the exact concepts PyCodeIt generates problems around

SQL Practice

Mastering SQL for Data and Backend Engineering Interviews

SQL is tested at every company that stores relational data, which is nearly all of them. PyCodeIt's live SQLite sandbox lets you write and verify queries against real table structures covering HR payroll, e-commerce orders, and competition scoring scenarios, giving you the hands-on experience interviewers actually probe for.

How SQL Interviews Differ from Coding Screens

A Python coding screen tests algorithmic thinking. A SQL screen tests relational thinking. Interviewers want to know whether you can reason about sets of rows rather than individual values, choose the right join type for a given scenario, and write queries that remain correct when the data grows or contains NULLs.

The most frequent mistakes are not syntax errors. They are logical errors: using the wrong join and not knowing which rows disappear, filtering after aggregation with WHERE instead of HAVING, or applying a window function without understanding its frame. PyCodeIt builds a structured question bank covering these exact traps from basic SELECT statements through advanced window functions and recursive CTEs.

Understanding the SQL Execution Order

SQL clauses are written in a specific order but executed in a different one. Knowing the logical processing sequence is the foundation of writing correct queries and explaining your reasoning to an interviewer.

  1. FROM and JOIN resolve the base row set, including any join filtering
  2. WHERE filters individual rows before any grouping happens
  3. GROUP BY collapses matching rows into a single summary row
  4. HAVING filters the collapsed groups based on aggregate values
  5. SELECT computes the expressions and column aliases you see in output
  6. ORDER BY sorts the final result, and it can reference aliases defined in SELECT
  7. LIMIT or TOP restricts the number of rows returned to the client

This order explains why you cannot use a SELECT alias inside a WHERE clause but you can use it inside ORDER BY. It also explains why window functions, which are evaluated after GROUP BY, can reference aggregated columns that WHERE cannot.

NULLs: The Behavior Most Candidates Get Wrong

NULL in SQL represents the absence of a value, not zero or an empty string. It propagates through arithmetic and comparisons in ways that surprise developers coming from Python or JavaScript. Any arithmetic involving NULL produces NULL. Any comparison using = or != against NULL returns UNKNOWN, not TRUE or FALSE.

  • Use IS NULL and IS NOT NULL to test for missing values, never = NULL
  • COUNT(*) counts all rows including NULLs; COUNT(column) skips NULLs in that column
  • COALESCE returns the first non-NULL value in its argument list and is the standard way to substitute a default
  • NULL values sort last in ascending order in PostgreSQL; behavior varies by database engine
  • Two rows with NULL in the join column will not match each other, which removes them from INNER JOINs

Data Analyst and Data Engineer Interviews

Analyst roles at companies like Airbnb, Stripe, and Shopify use SQL screens that test aggregations, cohort analysis, and retention queries. Engineer roles add window functions, query optimization, and schema design questions. The Mode Analytics SQL tutorial covers the analyst-focused patterns that pair well with PyCodeIt's structured problem bank.

Explore SQL practice →

Backend Engineering SQL Assessment Preparation

Backend engineers face schema design, index selection, and transaction isolation questions in addition to query writing. Understanding when a full table scan beats an index scan, how foreign key constraints enforce referential integrity, and what EXPLAIN output tells you are skills that separate senior candidates from junior ones.

Practice backend SQL →

University Coursework and Certification Preparation

Students preparing for database coursework at universities or pursuing certifications like Oracle Database SQL Certified Associate will find PyCodeIt's question bank covers normalization, join theory, and aggregate functions at the right depth for exam preparation.

Start certification prep →

Free SQL Learning Resources

The resources below are widely used by developers preparing for SQL interviews and complement the structured problem sets available in PyCodeIt's SQL playground:

  • W3Schools SQL reference provides runnable examples for every clause from basic SELECT through stored procedures
  • Mode Analytics SQL tutorial is particularly strong on window functions and business-oriented analytical patterns
  • PostgreSQL official tutorial is the most thorough coverage of a production-grade engine and is free to read online
  • Harvard CS50 SQL course offers a complete beginner-to-intermediate curriculum with graded problem sets at no cost
  • GeeksforGeeks SQL tutorials cover interview-specific patterns including joins, subqueries, and indexing with worked examples
User Reviews

What Our Community Says

Read ratings and experiences shared by students and professional engineers practicing on pycodeit.

Share Your Experience

PyCodeIt

Free interactive learning platform for Python code tracing, SQL queries, and technical interviews. Built for bootcamp grads, computer science students, and engineers.

Python Practice

  • Learning Center
  • For loop tracing
  • List tracing
  • Dictionary tracing
  • Decorators practice
  • Python Tracing Guide
  • Python Output Questions

SQL Practice

  • SQL Fundamentals
  • Relational JOINs
  • Window Functions
  • CTEs & Set Operators
  • SQL JOINs Guide
  • Window Functions Guide

Legal

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 PyCodeIt. Sandbox keys are processed strictly client-side.