[{"data":1,"prerenderedAt":265},["ShallowReactive",2],{"topic-sql-subqueries":3},{"framework":4,"topic":16,"subtopics":25},{"id":5,"description":6,"extension":7,"icon":8,"meta":9,"name":10,"order":11,"slug":12,"stem":13,"tier":14,"__hash__":15},"frameworks\u002Fframeworks\u002Fsql.yml","SQL interview questions on queries, joins and aggregation — essential for every backend, data and analytics interview.","yml","database",{},"SQL",4,"sql","frameworks\u002Fsql",1,"lpzsOj2p9p9W0Tctwc61nP-ulZAA80R5gJiyaZS6ZeI",{"id":17,"description":18,"extension":7,"frameworkSlug":12,"meta":19,"name":20,"order":21,"slug":22,"stem":23,"__hash__":24},"topics\u002Ftopics\u002Fsql-subqueries.yml","Scalar, correlated and nested subqueries, IN\u002FEXISTS, derived tables and common table expressions — composing queries out of other queries.",{},"Subqueries & CTEs",2,"subqueries","topics\u002Fsql-subqueries","FnPGLIAjadsROHZZpt6bZrsS7t3mh0gS-lVF9UAW1tY",[26,158],{"id":27,"title":28,"body":29,"description":64,"difficulty":67,"extension":68,"framework":10,"frameworkSlug":12,"meta":69,"navigation":70,"order":14,"path":71,"questions":72,"questionsCount":151,"related":152,"seo":153,"seoDescription":154,"stem":155,"subtopic":28,"topic":20,"topicSlug":22,"updated":156,"__hash__":157},"qa\u002Fsql\u002Fsubqueries\u002Fsubqueries.md","Subqueries",{"type":30,"value":31,"toc":63},"minimark",[32,37],[33,34,36],"h2",{"id":35},"about-sql-subqueries","About SQL Subqueries",[38,39,40,41,45,46,50,51,54,55,58,59,62],"p",{},"Subqueries let you compose a query out of the results of other queries — filtering on\nan aggregate, testing membership, or computing a per-row value inline. Mastering the\ndifference between ",[42,43,44],"strong",{},"scalar, correlated, and multi-row"," subqueries, and knowing when\n",[47,48,49],"code",{},"EXISTS"," beats ",[47,52,53],{},"IN"," (and why ",[47,56,57],{},"NOT IN"," is dangerous with ",[47,60,61],{},"NULL","s), is a staple of SQL\ninterviews.",{"title":64,"searchDepth":21,"depth":21,"links":65},"",[66],{"id":35,"depth":21,"text":36},"medium","md",{},true,"\u002Fsql\u002Fsubqueries\u002Fsubqueries",[73,78,82,86,90,94,98,103,107,111,115,119,123,127,131,135,139,143,147],{"id":74,"difficulty":75,"q":76,"a":77},"what-is-a-subquery","easy","What is a subquery in SQL?","A **subquery** (or inner query) is a `SELECT` statement nested inside another\nSQL statement. The database runs the inner query and feeds its result to the\n**outer query**. Subqueries can appear in the `SELECT`, `FROM`, `WHERE`, or\n`HAVING` clause.\n\n```sql\n-- find employees earning more than the company average\nSELECT name, salary\nFROM   employees\nWHERE  salary > (SELECT AVG(salary) FROM employees);  -- inner query first\n```\n\nThe parentheses are required, and a subquery is always **fully enclosed** in\nthem. The inner query here returns a single value the outer `WHERE` compares\nagainst.\n\nRule of thumb: a subquery lets you use the result of one query as an input to\nanother, without a temporary table.\n",{"id":79,"difficulty":75,"q":80,"a":81},"types-of-subqueries","What are the main types of subqueries?","Subqueries are classified by **what they return** and **whether they depend on\nthe outer query**:\n\n- **Scalar subquery** — returns a single value (one row, one column).\n- **Row subquery** — returns a single row of multiple columns.\n- **Table \u002F multi-row subquery** — returns many rows (used with `IN`, `ANY`, `EXISTS`).\n- **Correlated subquery** — references a column from the outer query, so it\n  re-runs per outer row.\n- **Non-correlated subquery** — self-contained; runs once independently.\n\n```sql\nSELECT (SELECT MAX(price) FROM products) AS top_price;  -- scalar\n```\n\nRule of thumb: classify a subquery by its cardinality (scalar \u002F row \u002F table)\nand its dependency (correlated \u002F not) — both drive which operators you can use\nand how it performs.\n",{"id":83,"difficulty":75,"q":84,"a":85},"scalar-subquery","What is a scalar subquery and where can you use it?","A **scalar subquery** returns **exactly one row and one column** — a single\nvalue. Because it resolves to a value, you can use it almost anywhere an\nexpression is allowed: `SELECT`, `WHERE`, `HAVING`, even inside arithmetic.\n\n```sql\nSELECT name,\n       salary,\n       salary - (SELECT AVG(salary) FROM employees) AS diff_from_avg\nFROM   employees;\n```\n\nIf a scalar subquery returns **more than one row**, the query errors at runtime\n(`more than one row returned by a subquery used as an expression`). If it\nreturns **no rows**, it yields `NULL`.\n\nRule of thumb: use a scalar subquery wherever you'd write a single value —\nguarantee it returns at most one row, often with an aggregate or `LIMIT 1`.\n",{"id":87,"difficulty":67,"q":88,"a":89},"correlated-subquery","What is a correlated subquery?","A **correlated subquery** references a column from the **outer query**, so it\ncannot run on its own — it is **re-evaluated once per outer row**. Conceptually\nit behaves like a loop.\n\n```sql\n-- employees who earn more than their own department's average\nSELECT e.name, e.salary, e.dept_id\nFROM   employees e\nWHERE  e.salary > (SELECT AVG(s.salary)\n                   FROM   employees s\n                   WHERE  s.dept_id = e.dept_id);  -- e.dept_id = outer ref\n```\n\nThe inner query depends on `e.dept_id`, which changes per outer row. This is\npowerful but can be **slow** on large tables because of the repeated execution\n(though modern optimizers often rewrite it as a join).\n\nRule of thumb: if the inner query mentions an outer table's column, it's\ncorrelated and runs per row — watch its cost.\n",{"id":91,"difficulty":67,"q":92,"a":93},"correlated-vs-non-correlated","What is the difference between a correlated and a non-correlated subquery?","A **non-correlated** subquery is independent — it runs **once**, and its result\nis reused by the outer query. A **correlated** subquery references the outer\nquery and runs **once per outer row**.\n\n```sql\n-- non-correlated: AVG computed a single time\nSELECT name FROM employees\nWHERE salary > (SELECT AVG(salary) FROM employees);\n\n-- correlated: inner query re-runs for each employee row\nSELECT name FROM employees e\nWHERE salary > (SELECT AVG(salary) FROM employees s\n                WHERE s.dept_id = e.dept_id);\n```\n\nYou can test the difference: a non-correlated subquery runs successfully on its\nown; a correlated one errors because the outer column is unknown.\n\nRule of thumb: non-correlated = compute once; correlated = compute per row.\nPrefer non-correlated (or a join) when you can.\n",{"id":95,"difficulty":67,"q":96,"a":97},"in-vs-exists","What is the difference between IN and EXISTS?","Both test membership, but differently. `IN` compares a column against the **list\nof values** a subquery returns. `EXISTS` checks whether the subquery returns\n**any row at all** (a boolean), and is typically **correlated**.\n\n```sql\n-- IN: builds a value list, then matches\nSELECT name FROM customers\nWHERE id IN (SELECT customer_id FROM orders);\n\n-- EXISTS: stops at the first matching row\nSELECT name FROM customers c\nWHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);\n```\n\n`EXISTS` can be faster on large subquery results because it **short-circuits**\nat the first match. `IN` is fine and readable for small, static lists. The big\ngotcha is `NOT IN` with `NULL`s (see the next question).\n\nRule of thumb: use `EXISTS` for correlated existence checks on big tables;\n`IN` for small value lists.\n",{"id":99,"difficulty":100,"q":101,"a":102},"not-in-null-trap","hard","Why can NOT IN behave unexpectedly with NULL values?","If the subquery (or list) behind `NOT IN` contains a single `NULL`, the **whole\n`NOT IN` returns no rows**. That's because `x NOT IN (a, b, NULL)` expands to\n`x \u003C> a AND x \u003C> b AND x \u003C> NULL`, and `x \u003C> NULL` is `UNKNOWN`, which makes the\nentire `AND` never `TRUE`.\n\n```sql\n-- if any customer_id is NULL, this returns ZERO rows unexpectedly\nSELECT name FROM customers\nWHERE id NOT IN (SELECT customer_id FROM orders);\n\n-- safe alternatives:\nSELECT name FROM customers c\nWHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);\n-- or filter the NULLs: ... WHERE customer_id IS NOT NULL\n```\n\n`NOT EXISTS` is **NULL-safe** and usually the right tool.\n\nRule of thumb: avoid `NOT IN` over a nullable column — use `NOT EXISTS` instead.\n",{"id":104,"difficulty":67,"q":105,"a":106},"any-all-operators","What do the ANY and ALL operators do with subqueries?","`ANY` (synonym `SOME`) and `ALL` compare a value against a **set** returned by a\nsubquery, combined with a comparison operator.\n\n- `> ANY (...)` → greater than **at least one** value (i.e. greater than the min).\n- `> ALL (...)` → greater than **every** value (i.e. greater than the max).\n\n```sql\n-- products pricier than the cheapest product in category 5\nSELECT name FROM products\nWHERE price > ANY (SELECT price FROM products WHERE category_id = 5);\n\n-- products pricier than ALL products in category 5\nSELECT name FROM products\nWHERE price > ALL (SELECT price FROM products WHERE category_id = 5);\n```\n\nNote `= ANY` is equivalent to `IN`, and `\u003C> ALL` is equivalent to `NOT IN`.\n\nRule of thumb: `ANY` = matches some; `ALL` = matches every — often clearer when\nrewritten with `MIN`\u002F`MAX`.\n",{"id":108,"difficulty":75,"q":109,"a":110},"subquery-in-where","How are subqueries used in the WHERE clause?","A `WHERE`-clause subquery **filters** outer rows using a value or set computed by\nthe inner query. The operator must match the subquery's cardinality: use `=`,\n`\u003C`, `>` with **scalar** subqueries, and `IN`\u002F`EXISTS`\u002F`ANY`\u002F`ALL` with\n**multi-row** subqueries.\n\n```sql\n-- scalar comparison\nSELECT name FROM products\nWHERE price > (SELECT AVG(price) FROM products);\n\n-- multi-row membership\nSELECT name FROM products\nWHERE category_id IN (SELECT id FROM categories WHERE active = true);\n```\n\nUsing `=` with a subquery that returns multiple rows is a runtime error.\n\nRule of thumb: scalar subquery → comparison operator; multi-row subquery →\n`IN`\u002F`EXISTS`\u002F`ANY`\u002F`ALL`.\n",{"id":112,"difficulty":67,"q":113,"a":114},"subquery-in-select","How do you use a subquery in the SELECT list?","A subquery in the `SELECT` list must be **scalar** — it produces one extra\ncomputed column per output row, and is usually **correlated** to the outer row.\n\n```sql\nSELECT c.name,\n       (SELECT COUNT(*) FROM orders o\n        WHERE o.customer_id = c.id) AS order_count\nFROM   customers c;\n```\n\nThis runs the inner `COUNT` for each customer. It's readable but can be slow at\nscale; a `LEFT JOIN ... GROUP BY` or window function is often faster.\n\n```sql\n-- usually faster equivalent\nSELECT c.name, COUNT(o.id) AS order_count\nFROM   customers c\nLEFT JOIN orders o ON o.customer_id = c.id\nGROUP BY c.name;\n```\n\nRule of thumb: a `SELECT`-list subquery is a convenient per-row lookup — switch\nto a join when performance matters.\n",{"id":116,"difficulty":67,"q":117,"a":118},"derived-table","What is a derived table (subquery in the FROM clause)?","A **derived table** is a subquery in the `FROM` clause that acts as a temporary,\ninline table for the outer query. It **must be given an alias**, and you can join\nto it or filter it like any table.\n\n```sql\n-- average order value per customer, then filter the big spenders\nSELECT customer_id, avg_value\nFROM (\n    SELECT customer_id, AVG(total) AS avg_value\n    FROM   orders\n    GROUP BY customer_id\n) AS customer_avgs            -- alias is mandatory\nWHERE avg_value > 500;\n```\n\nDerived tables let you **filter on aggregates** (which `WHERE` can't do directly)\nand break complex logic into stages. CTEs do the same thing with cleaner syntax.\n\nRule of thumb: use a derived table to compute an intermediate result set you then\nquery — always alias it.\n",{"id":120,"difficulty":67,"q":121,"a":122},"subquery-vs-join","When should you use a subquery versus a join?","They often produce the same result; choose by **readability and performance**.\n\n- **Join** — best when you need columns from **both** tables in the output, and\n  usually optimizes well. Can multiply rows if the relationship is one-to-many.\n- **Subquery** — best for **existence\u002Fmembership tests** (`EXISTS`, `IN`) or a\n  single computed value, where you don't want the other table's columns. Won't\n  accidentally duplicate rows.\n\n```sql\n-- subquery: just \"do they have orders?\" — no duplication\nSELECT name FROM customers c\nWHERE EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);\n\n-- join: need order details too\nSELECT c.name, o.total\nFROM customers c JOIN orders o ON o.customer_id = c.id;\n```\n\nMost optimizers rewrite `IN`\u002F`EXISTS` into semi-joins anyway, so they perform\nsimilarly.\n\nRule of thumb: need the other table's columns → join; just testing existence →\nsubquery.\n",{"id":124,"difficulty":67,"q":125,"a":126},"nested-subqueries","What are nested subqueries?","A **nested subquery** is a subquery that itself contains another subquery —\nqueries nested several levels deep. The innermost runs first, feeding its result\noutward.\n\n```sql\n-- customers in the region with the highest total sales\nSELECT name FROM customers\nWHERE region_id = (\n    SELECT region_id FROM sales\n    GROUP BY region_id\n    ORDER BY SUM(amount) DESC\n    LIMIT 1\n);\n```\n\nMost databases allow many levels of nesting, but deep nesting hurts readability\nand can hurt performance. **CTEs** are the standard cure — they flatten nested\nlogic into named, sequential steps.\n\nRule of thumb: a couple of nesting levels is fine; beyond that, refactor into\nCTEs for clarity.\n",{"id":128,"difficulty":75,"q":129,"a":130},"subquery-returns-multiple-rows-error","Why does \"subquery returns more than one row\" error occur?","This error means you used a subquery in a **scalar context** (with `=`, `\u003C`, `>`,\nor in the `SELECT` list), but it returned **more than one row**. A scalar context\nexpects a single value.\n\n```sql\n-- ERROR if multiple employees share the max salary\nSELECT name FROM employees\nWHERE salary = (SELECT salary FROM employees ORDER BY salary DESC);\n\n-- fixes: aggregate, LIMIT, or switch operator\nWHERE salary = (SELECT MAX(salary) FROM employees);   -- scalar\nWHERE salary IN (SELECT salary FROM employees ORDER BY salary DESC LIMIT 5);\n```\n\nEither guarantee one row (`MAX`, `LIMIT 1`) or use a set operator (`IN`, `ANY`).\n\nRule of thumb: scalar operators need a one-row subquery — add an aggregate or\n`LIMIT`, or switch to `IN`.\n",{"id":132,"difficulty":67,"q":133,"a":134},"subquery-execution-order","In what order are subqueries executed?","Conceptually, a **non-correlated** subquery runs **first**, once, and its result\nis substituted into the outer query. A **correlated** subquery runs **per outer\nrow**, after the outer row is available.\n\n```sql\n-- non-correlated inner query evaluated once, then outer filters\nSELECT name FROM products\nWHERE price > (SELECT AVG(price) FROM products);\n```\n\nIn practice the **query optimizer** decides the real execution plan — it may\nrewrite a subquery as a join, cache a correlated result, or reorder operations.\nThe logical \"inner first\" model is for reasoning, not a literal guarantee.\n\nRule of thumb: reason as \"inner first (or per-row if correlated),\" but trust the\noptimizer for the actual plan — check `EXPLAIN`.\n",{"id":136,"difficulty":100,"q":137,"a":138},"correlated-subquery-performance","How can you improve the performance of a correlated subquery?","Correlated subqueries re-run per outer row, so the fixes reduce that repetition:\n\n- **Rewrite as a join** (often a semi-join) or a derived table aggregated once.\n- **Index** the correlated column the inner query filters on.\n- Use **window functions** to compute per-group values in a single pass.\n\n```sql\n-- correlated (per-row AVG):\nSELECT name FROM employees e\nWHERE salary > (SELECT AVG(salary) FROM employees s WHERE s.dept_id = e.dept_id);\n\n-- window-function rewrite (single pass):\nSELECT name FROM (\n    SELECT name, salary, AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg\n    FROM employees\n) t\nWHERE salary > dept_avg;\n```\n\nRule of thumb: if a correlated subquery is hot, rewrite it as a join or window\nfunction and index the join key.\n",{"id":140,"difficulty":67,"q":141,"a":142},"subquery-in-having","Can you use a subquery in the HAVING clause?","Yes. A `HAVING` subquery filters **groups** by comparing an aggregate against a\nvalue the subquery computes — useful when the threshold itself comes from a query.\n\n```sql\n-- departments whose average salary beats the company-wide average\nSELECT dept_id, AVG(salary) AS dept_avg\nFROM   employees\nGROUP  BY dept_id\nHAVING AVG(salary) > (SELECT AVG(salary) FROM employees);\n```\n\nThe subquery here is scalar and non-correlated, computed once. `HAVING` runs\nafter grouping, so it can compare group aggregates to the subquery's value.\n\nRule of thumb: use a `HAVING` subquery when you filter groups against a value\ncomputed elsewhere.\n",{"id":144,"difficulty":67,"q":145,"a":146},"subquery-with-insert-update-delete","Can subqueries be used in INSERT, UPDATE, and DELETE statements?","Yes — subqueries work in DML, not just `SELECT`.\n\n```sql\n-- INSERT ... SELECT\nINSERT INTO archived_orders\nSELECT * FROM orders WHERE created_at \u003C '2024-01-01';\n\n-- UPDATE with a correlated subquery\nUPDATE products p\nSET    avg_category_price = (SELECT AVG(price) FROM products x\n                             WHERE x.category_id = p.category_id);\n\n-- DELETE using a subquery in WHERE\nDELETE FROM customers\nWHERE id NOT IN (SELECT customer_id FROM orders WHERE customer_id IS NOT NULL);\n```\n\nThis lets you drive modifications off other tables' data. Watch the `NOT IN`\u002FNULL\ntrap in `DELETE`.\n\nRule of thumb: subqueries make DML data-driven — `INSERT ... SELECT`, correlated\n`UPDATE`, and `WHERE` subqueries in `DELETE`.\n",{"id":148,"difficulty":67,"q":149,"a":150},"subquery-vs-cte","What is the difference between a subquery and a CTE?","A **CTE** (Common Table Expression, `WITH` clause) is a named, reusable result set\ndefined before the main query. A **subquery** is inline and anonymous. They're\nlogically similar — a CTE is often just a more readable derived table.\n\n```sql\n-- subquery (derived table)\nSELECT * FROM (SELECT dept_id, AVG(salary) a FROM employees GROUP BY dept_id) t\nWHERE a > 50000;\n\n-- CTE equivalent\nWITH dept_avg AS (\n    SELECT dept_id, AVG(salary) AS a FROM employees GROUP BY dept_id\n)\nSELECT * FROM dept_avg WHERE a > 50000;\n```\n\nA CTE can be **referenced multiple times** in the same query, supports\n**recursion**, and reads top-to-bottom — advantages a derived table lacks.\n\nRule of thumb: reach for a CTE when the logic is reused, recursive, or complex\nenough that names aid readability; a subquery for quick one-off nesting.\n",19,null,{"description":64},"SQL subquery interview questions — scalar vs correlated subqueries, IN vs EXISTS, derived tables, subqueries in SELECT\u002FFROM\u002FWHERE, and performance.","sql\u002Fsubqueries\u002Fsubqueries","2026-06-20","orQNx0a4_px7--wFgVCQ4cieuTolAE9lZKNbU6YrfuE",{"id":159,"title":160,"body":161,"description":64,"difficulty":67,"extension":68,"framework":10,"frameworkSlug":12,"meta":181,"navigation":70,"order":21,"path":182,"questions":183,"questionsCount":151,"related":152,"seo":260,"seoDescription":261,"stem":262,"subtopic":263,"topic":20,"topicSlug":22,"updated":156,"__hash__":264},"qa\u002Fsql\u002Fsubqueries\u002Fctes.md","Ctes",{"type":30,"value":162,"toc":178},[163,167],[33,164,166],{"id":165},"about-common-table-expressions","About Common Table Expressions",[38,168,169,170,173,174,177],{},"CTEs (the ",[47,171,172],{},"WITH"," clause) turn deeply nested subqueries into readable, top-to-bottom\npipelines, and — uniquely — enable ",[42,175,176],{},"recursion"," for hierarchical data like org charts\nand category trees. Interviewers probe whether you understand a CTE's single-statement\nscope, how it differs from views and temp tables, the anchor\u002Frecursive structure of a\nrecursive CTE, and the reality that CTEs are mainly a readability tool, not a magic\nperformance boost.",{"title":64,"searchDepth":21,"depth":21,"links":179},[180],{"id":165,"depth":21,"text":166},{},"\u002Fsql\u002Fsubqueries\u002Fctes",[184,188,192,196,200,204,208,212,216,220,224,228,232,236,240,244,248,252,256],{"id":185,"difficulty":75,"q":186,"a":187},"what-is-a-cte","What is a Common Table Expression (CTE)?","A **CTE** is a named temporary result set, defined with the `WITH` clause, that\nexists only for the duration of a single statement. You define it once, then\nreference it by name in the query that follows — like a disposable, inline view.\n\n```sql\nWITH recent_orders AS (\n    SELECT * FROM orders WHERE created_at > '2026-01-01'\n)\nSELECT customer_id, COUNT(*)\nFROM   recent_orders          -- reference the CTE by name\nGROUP  BY customer_id;\n```\n\nCTEs make complex queries **readable** by breaking them into named, top-to-bottom\nsteps instead of deeply nested subqueries.\n\nRule of thumb: a CTE is a named subquery you define up front with `WITH` to make a\nquery read like sequential steps.\n",{"id":189,"difficulty":75,"q":190,"a":191},"cte-syntax","What is the syntax of a CTE?","A CTE starts with `WITH`, names the result set, and defines it in parentheses;\nthe main query follows and references the name.\n\n```sql\nWITH cte_name (optional, col, list) AS (\n    SELECT ...               -- the CTE body\n)\nSELECT * FROM cte_name;      -- the main query MUST follow immediately\n```\n\nKey rules: the main statement must come **right after** the CTE definition; the\noptional column list renames the output columns; and the CTE is only visible to\nthe statement it's attached to.\n\nRule of thumb: `WITH name AS (...)` then the query — the CTE and its consumer are\none statement.\n",{"id":193,"difficulty":67,"q":194,"a":195},"cte-vs-subquery","What is the difference between a CTE and a subquery?","Functionally a CTE is similar to a derived-table subquery, but it offers things a\nplain subquery can't:\n\n- **Reusability** — reference the same CTE multiple times in one query; a derived\n  table must be repeated.\n- **Readability** — named, top-to-bottom steps instead of inside-out nesting.\n- **Recursion** — only CTEs can be recursive.\n\n```sql\n-- a subquery repeated twice...\nSELECT * FROM (SELECT ...) a JOIN (SELECT ...) b ON ...;\n\n-- ...vs a CTE defined once, used twice\nWITH t AS (SELECT ...)\nSELECT * FROM t a JOIN t b ON ...;\n```\n\nPerformance is usually comparable — many engines treat a CTE as syntactic sugar\nfor a subquery.\n\nRule of thumb: prefer a CTE when logic is reused, recursive, or complex enough\nthat naming the steps helps.\n",{"id":197,"difficulty":67,"q":198,"a":199},"cte-vs-view","What is the difference between a CTE and a view?","Both name a query, but their **scope and persistence** differ:\n\n- A **view** is a permanent schema object, stored in the catalog and reusable by\n  **any** query and user, until dropped.\n- A **CTE** is temporary and **scoped to a single statement** — it vanishes when\n  the query finishes and isn't stored anywhere.\n\n```sql\n-- view: created once, reused forever\nCREATE VIEW active_customers AS SELECT * FROM customers WHERE active = true;\n\n-- CTE: lives only inside this one statement\nWITH active_customers AS (SELECT * FROM customers WHERE active = true)\nSELECT * FROM active_customers;\n```\n\nRule of thumb: reuse across many queries → create a view; one-off, query-local\nlogic → use a CTE.\n",{"id":201,"difficulty":67,"q":202,"a":203},"multiple-ctes","Can you define multiple CTEs in one query?","Yes. Write a single `WITH`, then separate each CTE definition with a **comma**.\nThey're listed top-to-bottom and any CTE can reference the ones **defined before\nit**.\n\n```sql\nWITH dept_avg AS (\n    SELECT dept_id, AVG(salary) AS avg_sal\n    FROM   employees GROUP BY dept_id\n),\nhigh_paying AS (\n    SELECT dept_id FROM dept_avg WHERE avg_sal > 80000  -- uses dept_avg\n)\nSELECT e.name\nFROM   employees e\nJOIN   high_paying h ON e.dept_id = h.dept_id;\n```\n\nOnly one `WITH` keyword is needed regardless of how many CTEs follow.\n\nRule of thumb: chain CTEs with commas to build a pipeline of named steps, each\nable to use the ones above it.\n",{"id":205,"difficulty":67,"q":206,"a":207},"cte-chaining","How do you chain CTEs to build a multi-step pipeline?","Because a CTE can reference earlier CTEs, you can express a **data pipeline** as a\nsequence of transformations — each step reads cleanly off the previous one.\n\n```sql\nWITH raw AS (\n    SELECT customer_id, total FROM orders WHERE status = 'paid'\n),\nper_customer AS (\n    SELECT customer_id, SUM(total) AS spend FROM raw GROUP BY customer_id\n),\nranked AS (\n    SELECT customer_id, spend,\n           RANK() OVER (ORDER BY spend DESC) AS rnk\n    FROM per_customer\n)\nSELECT * FROM ranked WHERE rnk \u003C= 10;   -- top 10 spenders\n```\n\nThis is far more readable than three levels of nested subqueries.\n\nRule of thumb: model ETL-style logic as chained CTEs — filter, aggregate, rank,\nthen select.\n",{"id":209,"difficulty":100,"q":210,"a":211},"recursive-cte","What is a recursive CTE?","A **recursive CTE** references **itself** to process hierarchical or iterative\ndata — org charts, category trees, graph traversal, or number\u002Fdate series. It's\ndeclared with `WITH RECURSIVE` (the keyword is optional in SQL Server).\n\n```sql\nWITH RECURSIVE subordinates AS (\n    SELECT id, name, manager_id          -- anchor: the starting row(s)\n    FROM   employees WHERE id = 1\n    UNION ALL\n    SELECT e.id, e.name, e.manager_id    -- recursive: joins back to the CTE\n    FROM   employees e\n    JOIN   subordinates s ON e.manager_id = s.id\n)\nSELECT * FROM subordinates;\n```\n\nIt runs the anchor once, then repeatedly runs the recursive part against the\nprevious result until no new rows appear.\n\nRule of thumb: use a recursive CTE to walk hierarchies and trees that a flat\n`JOIN` can't express.\n",{"id":213,"difficulty":100,"q":214,"a":215},"recursive-cte-parts","What are the two parts of a recursive CTE?","A recursive CTE has two members joined by `UNION ALL`:\n\n1. **Anchor member** — the non-recursive base case; runs **once** to seed the\n   result (e.g. the root of a tree).\n2. **Recursive member** — references the CTE itself; runs **repeatedly**, each\n   iteration operating on the rows the previous iteration produced.\n\n```sql\nWITH RECURSIVE nums AS (\n    SELECT 1 AS n                     -- anchor\n    UNION ALL\n    SELECT n + 1 FROM nums WHERE n \u003C 5 -- recursive, with a stop condition\n)\nSELECT n FROM nums;   -- 1,2,3,4,5\n```\n\nThe recursive member **must** have a terminating condition or the query loops\nuntil it hits the recursion limit.\n\nRule of thumb: anchor seeds, recursive member iterates, `UNION ALL` glues them —\nalways include a stopping condition.\n",{"id":217,"difficulty":100,"q":218,"a":219},"recursive-cte-infinite-loop","How do you prevent an infinite loop in a recursive CTE?","A recursive CTE loops forever if the recursive member never stops producing new\nrows — common with **cyclic data** (A reports to B, B reports to A).\n\nDefenses:\n- A **terminating predicate** in the recursive member (`WHERE n \u003C 100`,\n  `WHERE level \u003C 10`).\n- Track a **path \u002F visited set** and exclude already-seen nodes to break cycles.\n- Rely on the engine's **recursion limit** as a safety net (Postgres has no hard\n  default but you can `LIMIT`; SQL Server defaults to `MAXRECURSION 100`).\n\n```sql\n-- SQL Server: cap iterations explicitly\nSELECT * FROM subordinates OPTION (MAXRECURSION 50);\n```\n\nRule of thumb: every recursive CTE needs a stop condition; for graphs that may\ncontain cycles, also track visited nodes.\n",{"id":221,"difficulty":67,"q":222,"a":223},"cte-multiple-references","Can a CTE be referenced multiple times in the same query?","Yes — a key advantage over a derived table. Define the CTE once and use its name\nas many times as needed, including **self-joins**.\n\n```sql\n-- compare each employee's salary to their manager's, using one CTE twice\nWITH emp AS (\n    SELECT id, name, salary, manager_id FROM employees\n)\nSELECT e.name, e.salary, m.salary AS manager_salary\nFROM   emp e\nJOIN   emp m ON e.manager_id = m.id;\n```\n\nWhether the engine computes the CTE once and caches it or re-evaluates per\nreference depends on the database and whether it's materialized.\n\nRule of thumb: reuse a CTE by name instead of copy-pasting the same subquery —\ndefine once, reference freely.\n",{"id":225,"difficulty":100,"q":226,"a":227},"cte-materialization","Are CTEs materialized or inlined?","It depends on the database. **Materialized** means the CTE is computed once into a\ntemporary work table; **inlined** means it's folded into the main query and\noptimized together (often faster, since predicates can push down).\n\n- **PostgreSQL** — inlined since v12 when referenced once and not recursive; before\n  v12, CTEs were an **optimization fence** (always materialized). You can force\n  either with `MATERIALIZED` \u002F `NOT MATERIALIZED`.\n- **SQL Server \u002F MySQL 8+** — generally inline CTEs into the plan.\n\n```sql\n-- Postgres: force materialization (an optimization barrier)\nWITH t AS MATERIALIZED (SELECT * FROM big_table WHERE active)\nSELECT * FROM t WHERE id = 5;\n```\n\nRule of thumb: don't assume a CTE is materialized — check `EXPLAIN`; in modern\nPostgres use `MATERIALIZED`\u002F`NOT MATERIALIZED` to control it.\n",{"id":229,"difficulty":100,"q":230,"a":231},"cte-performance","Do CTEs improve query performance?","Not inherently — CTEs are primarily a **readability** tool. In most engines a CTE\nproduces the same plan as the equivalent subquery or derived table.\n\nCaveats that can hurt or help:\n- An **older Postgres** materializing a CTE could **block predicate pushdown**,\n  making it slower than an inline subquery.\n- A CTE **referenced many times** that the engine recomputes each time can be\n  slower than expected — materializing it once may help.\n- Recursive CTEs over deep hierarchies can be expensive regardless.\n\nRule of thumb: choose CTEs for clarity, not speed; verify with `EXPLAIN` and\nconsider explicit materialization only when the plan shows a problem.\n",{"id":233,"difficulty":67,"q":234,"a":235},"cte-in-update-delete","Can CTEs be used with INSERT, UPDATE, and DELETE?","Yes. Put the `WITH` clause in front of the DML statement and reference the CTE in\nit — handy for staging the rows to modify.\n\n```sql\n-- delete all but the latest order per customer\nWITH ranked AS (\n    SELECT id, ROW_NUMBER() OVER (PARTITION BY customer_id\n                                  ORDER BY created_at DESC) AS rn\n    FROM orders\n)\nDELETE FROM orders\nWHERE id IN (SELECT id FROM ranked WHERE rn > 1);\n```\n\nPostgres even allows **data-modifying CTEs** (`INSERT\u002FUPDATE\u002FDELETE ... RETURNING`\ninside a `WITH`), letting one statement write to several tables.\n\nRule of thumb: use a CTE to compute exactly which rows a DML statement should\ntouch — especially with window functions for \"keep the latest\" logic.\n",{"id":237,"difficulty":67,"q":238,"a":239},"cte-window-functions","Why are CTEs often paired with window functions?","Window functions like `ROW_NUMBER()` and `RANK()` **can't be used directly in\n`WHERE`** (they're computed after filtering). A CTE (or derived table) lets you\ncompute the window value first, then filter on it in the outer query.\n\n```sql\n-- top 3 earners per department\nWITH ranked AS (\n    SELECT name, dept_id, salary,\n           ROW_NUMBER() OVER (PARTITION BY dept_id\n                              ORDER BY salary DESC) AS rn\n    FROM employees\n)\nSELECT name, dept_id, salary\nFROM   ranked\nWHERE  rn \u003C= 3;       -- filter on the window result\n```\n\nRule of thumb: compute the window function in a CTE, then filter its alias in the\nouter query — the standard \"top-N-per-group\" pattern.\n",{"id":241,"difficulty":75,"q":242,"a":243},"cte-scope","What is the scope of a CTE?","A CTE is visible **only within the single statement** it's attached to. Once that\nstatement finishes, the CTE is gone — you can't reference it from a later\nstatement, and it isn't stored in the schema.\n\n```sql\nWITH t AS (SELECT 1 AS x)\nSELECT * FROM t;     -- works\n\nSELECT * FROM t;     -- ERROR: t no longer exists\n```\n\nAlso, later CTEs in the same `WITH` can see earlier ones, but not vice versa\n(except a recursive CTE referencing itself).\n\nRule of thumb: a CTE lives and dies with one statement — for cross-statement reuse\nuse a view or temp table.\n",{"id":245,"difficulty":75,"q":246,"a":247},"cte-column-aliasing","How do you rename a CTE's output columns?","Provide an explicit **column list** in parentheses after the CTE name. The CTE\nbody's columns are mapped positionally to those names — useful when the body uses\nexpressions or you want clearer names.\n\n```sql\nWITH sales (region, total) AS (\n    SELECT region_id, SUM(amount)\n    FROM   orders\n    GROUP  BY region_id\n)\nSELECT region, total FROM sales ORDER BY total DESC;\n```\n\nThe number of names must match the number of output columns. This is also the\nstandard way to name the columns of a **recursive** CTE.\n\nRule of thumb: add `(col1, col2, ...)` after the CTE name to give its columns\nexplicit names — required when the body's columns are unnamed expressions.\n",{"id":249,"difficulty":67,"q":250,"a":251},"cte-vs-temp-table","What is the difference between a CTE and a temporary table?","Both hold an intermediate result, but their lifetime and storage differ:\n\n- A **CTE** is logical and scoped to one statement; it isn't physically stored\n  (unless the engine materializes it internally) and can't be indexed.\n- A **temp table** is a real table in `tempdb`\u002Fsession scope, persists for the\n  **session\u002Ftransaction**, can be **indexed**, and is reusable across multiple\n  statements.\n\n```sql\n-- temp table: reusable across statements, can index\nCREATE TEMP TABLE big_spenders AS\n    SELECT customer_id, SUM(total) s FROM orders GROUP BY customer_id;\nCREATE INDEX ON big_spenders (s);\nSELECT * FROM big_spenders WHERE s > 1000;\n```\n\nRule of thumb: one-statement, no-index logic → CTE; reuse across statements or\nneed an index on the intermediate → temp table.\n",{"id":253,"difficulty":67,"q":254,"a":255},"cte-recursive-use-cases","What are common use cases for recursive CTEs?","Recursive CTEs shine wherever data is **hierarchical or generated iteratively**:\n\n- **Org charts \u002F management chains** — all reports under a manager.\n- **Category \u002F comment trees** — nested parent-child structures.\n- **Bill of materials** — parts made of sub-parts.\n- **Graph traversal** — shortest path, connected nodes.\n- **Generating series** — number ranges or contiguous date sequences.\n\n```sql\n-- generate every date in a month\nWITH RECURSIVE d AS (\n    SELECT DATE '2026-06-01' AS day\n    UNION ALL\n    SELECT day + 1 FROM d WHERE day \u003C DATE '2026-06-30'\n)\nSELECT day FROM d;\n```\n\nRule of thumb: reach for a recursive CTE whenever you'd otherwise need a loop to\nwalk a tree, graph, or generated series.\n",{"id":257,"difficulty":67,"q":258,"a":259},"when-not-to-use-cte","When should you avoid using a CTE?","CTEs are great for clarity, but they aren't always the right tool:\n\n- When you need the intermediate **reused across multiple statements** — a view or\n  temp table fits better.\n- When you need an **index** on the intermediate result — use a temp table.\n- On **older Postgres**, when materialization would block predicate pushdown and\n  slow the query — an inline subquery may be faster.\n- For a trivial one-liner where a simple subquery is just as clear.\n\nRule of thumb: use CTEs for readable, single-statement logic; switch to views or\ntemp tables when you need persistence, reuse, or indexing.\n",{"description":64},"SQL CTE interview questions — the WITH clause, recursive CTEs, CTE vs subquery vs view, materialization, multiple CTEs and chaining, and performance.","sql\u002Fsubqueries\u002Fctes","Common Table Expressions (CTEs)","b36Ff8SVYX5Lj0B-Q5_So2hKhCvupG7vokR_m7ylLp4",1782244097913]