[{"data":1,"prerenderedAt":114},["ShallowReactive",2],{"qa-\u002Fsql\u002Fbasics\u002Fset-operations":3},{"page":4,"siblings":94,"blog":111},{"id":5,"title":6,"body":7,"description":11,"difficulty":14,"extension":15,"framework":16,"frameworkSlug":17,"meta":18,"navigation":19,"order":20,"path":21,"questions":22,"questionsCount":85,"related":86,"seo":87,"seoDescription":88,"stem":89,"subtopic":6,"topic":90,"topicSlug":91,"updated":92,"__hash__":93},"qa\u002Fsql\u002Fbasics\u002Fset-operations.md","Set Operations",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"medium","md","SQL","sql",{},true,5,"\u002Fsql\u002Fbasics\u002Fset-operations",[23,28,32,36,40,44,48,52,56,60,65,69,73,77,81],{"id":24,"difficulty":25,"q":26,"a":27},"what-are-set-operations","easy","What are SQL set operations?","Set operations combine the results of **two or more `SELECT` queries vertically** —\nstacking or comparing rows rather than joining columns. The three are `UNION`\n(combine), `INTERSECT` (common rows), and `EXCEPT`\u002F`MINUS` (difference).\n\n```sql\nSELECT id FROM current_users\nUNION\nSELECT id FROM archived_users;   -- all ids from either table\n```\n\nBoth queries must produce **compatible columns** (same count, compatible types).\nSet operations work on whole rows, like mathematical set algebra.\n\nRule of thumb: joins combine tables side-by-side; set operations stack them\ntop-to-bottom.\n",{"id":29,"difficulty":25,"q":30,"a":31},"union-vs-union-all","What is the difference between UNION and UNION ALL?","`UNION` combines the rows of both queries and **removes duplicates**; `UNION ALL`\nkeeps **every row**, including duplicates. Because dedup requires a sort\u002Fhash,\n`UNION` is slower.\n\n```sql\n-- deduped: a user in both lists appears once\nSELECT email FROM newsletter UNION SELECT email FROM customers;\n\n-- all rows kept; faster, but duplicates remain\nSELECT email FROM newsletter UNION ALL SELECT email FROM customers;\n```\n\nUse `UNION ALL` when you know the inputs are disjoint or duplicates are fine — it\nskips the expensive dedup step.\n\nRule of thumb: default to `UNION ALL` unless you specifically need duplicates\nremoved.\n",{"id":33,"difficulty":14,"q":34,"a":35},"column-compatibility","What rules must the queries in a UNION satisfy?","Each query must have the **same number of columns**, in the **same order**, with\n**compatible data types** positionally. Column *names* needn't match — the result\ntakes its names from the **first** query.\n\n```sql\nSELECT id, name        FROM employees\nUNION ALL\nSELECT id, full_name   FROM contractors;   -- result columns: id, name\n```\n\nType mismatches either error or force an implicit cast. If a query has fewer\ncolumns, add literals\u002F`NULL`s to line them up.\n\nRule of thumb: align column count, order, and types; names come from the first\nquery.\n",{"id":37,"difficulty":14,"q":38,"a":39},"intersect","What does INTERSECT do?","`INTERSECT` returns only the rows that appear in **both** result sets, deduplicated.\nIt's the set intersection of the two queries.\n\n```sql\n-- users who are both newsletter subscribers AND customers\nSELECT email FROM newsletter\nINTERSECT\nSELECT email FROM customers;\n```\n\nLike `UNION`, it dedupes by default; `INTERSECT ALL` (where supported) keeps the\nminimum count of duplicates. MySQL gained `INTERSECT` in 8.0.31; older versions\nemulate it with `IN`\u002F`EXISTS`.\n\nRule of thumb: `INTERSECT` = \"rows present in both queries.\"\n",{"id":41,"difficulty":14,"q":42,"a":43},"except-minus","What do EXCEPT and MINUS do?","`EXCEPT` (Postgres\u002FSQL Server\u002Fstandard) and `MINUS` (Oracle) return rows from the\n**first** query that are **not** in the second — set difference. They're the same\noperation under two names.\n\n```sql\n-- users who signed up but never ordered\nSELECT id FROM users\nEXCEPT\nSELECT user_id FROM orders;\n```\n\nOrder matters: `A EXCEPT B` ≠ `B EXCEPT A`. It dedupes by default; `EXCEPT ALL`\nkeeps duplicate multiplicity. It's a clean way to express an anti-join when you only\nneed the keys.\n\nRule of thumb: `EXCEPT`\u002F`MINUS` = \"rows in the first query but not the second.\"\n",{"id":45,"difficulty":14,"q":46,"a":47},"union-null-handling","How do set operations treat NULLs in deduplication?","For deduplication, set operations treat two `NULL`s as **equal** (unlike `=`, where\n`NULL = NULL` is unknown). So `UNION`\u002F`INTERSECT`\u002F`EXCEPT` collapse duplicate\nNULL-containing rows.\n\n```sql\n-- the two NULL rows are treated as duplicates and collapse to one\nSELECT NULL AS x UNION SELECT NULL;   -- returns a single NULL row\n```\n\nThis \"NULL-as-equal\" rule is why `EXCEPT` works as an anti-join even with NULLs,\nwhereas `NOT IN` famously breaks on them.\n\nRule of thumb: set operations consider NULLs equal for dedup; row comparisons (`=`)\ndon't.\n",{"id":49,"difficulty":14,"q":50,"a":51},"order-by-with-union","How do you sort or limit the result of a UNION?","Apply `ORDER BY` \u002F `LIMIT` to the **whole combined result**, once, at the very end —\nnot to the individual `SELECT`s. The sort refers to the result columns (by name or\nposition).\n\n```sql\nSELECT name, created_at FROM users\nUNION ALL\nSELECT name, created_at FROM archived_users\nORDER BY created_at DESC\nLIMIT 20;\n```\n\nTo order *within* a branch (e.g. limit each side), wrap each `SELECT` in a subquery\nor CTE first.\n\nRule of thumb: one trailing `ORDER BY`\u002F`LIMIT` applies to the entire set result.\n",{"id":53,"difficulty":25,"q":54,"a":55},"union-vs-join","When do you use UNION instead of a JOIN?","Use `UNION` to **append rows** from sources with the **same shape** (current +\narchived orders, multiple regions' tables). Use a `JOIN` to **add columns** by\nrelating rows across tables on a key.\n\n```sql\n-- UNION: more rows, same columns\nSELECT id, total FROM orders_2025\nUNION ALL\nSELECT id, total FROM orders_2026;\n```\n\nA telltale sign you want `UNION` is \"combine these similarly-structured datasets into\none list.\"\n\nRule of thumb: same columns, more rows → `UNION`; related tables, more columns →\n`JOIN`.\n",{"id":57,"difficulty":14,"q":58,"a":59},"union-performance","Why is UNION ALL faster than UNION?","`UNION` must **deduplicate** the combined result, which means sorting or hashing all\nrows — extra CPU and memory. `UNION ALL` simply concatenates the inputs and streams\nthem out, with no dedup step.\n\n```sql\n-- no dedup work; fastest when you know rows can't overlap\nSELECT id FROM a UNION ALL SELECT id FROM b;\n```\n\nOn large datasets the difference is significant. Only pay for `UNION` when duplicates\nare actually possible and unwanted.\n\nRule of thumb: prefer `UNION ALL` and only upgrade to `UNION` when dedup is truly\nneeded.\n",{"id":61,"difficulty":62,"q":63,"a":64},"emulate-intersect-mysql","hard","How do you emulate INTERSECT or EXCEPT without native support?","Where `INTERSECT`\u002F`EXCEPT` aren't available (older MySQL), use `IN`\u002F`EXISTS` for\nintersection and `NOT EXISTS`\u002F`LEFT JOIN ... IS NULL` for difference.\n\n```sql\n-- INTERSECT emulation\nSELECT DISTINCT email FROM newsletter n\nWHERE EXISTS (SELECT 1 FROM customers c WHERE c.email = n.email);\n\n-- EXCEPT emulation\nSELECT DISTINCT id FROM users u\nWHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.user_id = u.id);\n```\n\nPrefer `EXISTS`\u002F`NOT EXISTS` over `IN`\u002F`NOT IN` here to stay NULL-safe.\n\nRule of thumb: emulate `INTERSECT` with `EXISTS`, `EXCEPT` with `NOT EXISTS`.\n",{"id":66,"difficulty":62,"q":67,"a":68},"precedence-set-ops","What is the precedence of set operators when you chain them?","The SQL standard gives `INTERSECT` **higher precedence** than `UNION` and `EXCEPT`,\nso `INTERSECT` binds first. When mixing them, use **parentheses** to make the\nintended grouping explicit.\n\n```sql\n-- ambiguous to readers — parenthesize instead\n(SELECT id FROM a UNION SELECT id FROM b)\nEXCEPT\nSELECT id FROM c;\n```\n\nDifferent databases have followed the rule inconsistently over the years, so never\nrely on implicit precedence in a chain.\n\nRule of thumb: parenthesize any query that mixes `UNION`\u002F`INTERSECT`\u002F`EXCEPT`.\n",{"id":70,"difficulty":25,"q":71,"a":72},"union-distinct-keyword","Is there a difference between UNION and UNION DISTINCT?","No — `UNION` and `UNION DISTINCT` are **identical**; `DISTINCT` is just the explicit\ndefault. Some teams write `UNION DISTINCT` to make the dedup intent obvious next to\n`UNION ALL`.\n\n```sql\nSELECT id FROM a UNION DISTINCT SELECT id FROM b;  -- same as plain UNION\n```\n\nLikewise `INTERSECT`\u002F`EXCEPT` default to `DISTINCT`, with optional `ALL` variants.\n\nRule of thumb: `UNION` already means `UNION DISTINCT`; write `ALL` when you want\nduplicates.\n",{"id":74,"difficulty":14,"q":75,"a":76},"combining-different-tables","How do you tag which source each UNION row came from?","Add a **literal column** in each branch to label the source. After combining, that\ncolumn tells you where each row originated.\n\n```sql\nSELECT id, total, 'online'  AS channel FROM online_orders\nUNION ALL\nSELECT id, total, 'instore' AS channel FROM instore_orders;\n```\n\nThis is handy for merging similar feeds while keeping provenance, and lets you later\nfilter or group by `channel`.\n\nRule of thumb: add a constant label column per branch to track each row's source.\n",{"id":78,"difficulty":14,"q":79,"a":80},"distinct-vs-union","Is SELECT DISTINCT the same as UNION for one query?","They overlap but aren't the same. `UNION` dedups across **two** queries; for a\n**single** query, `SELECT DISTINCT` dedups its rows. `SELECT ... UNION SELECT ...`\nwith one branch is just a slow `DISTINCT`.\n\n```sql\n-- these return the same rows; the second is clearer\nSELECT city FROM users UNION SELECT city FROM users;\nSELECT DISTINCT city FROM users;\n```\n\nUse `DISTINCT` for single-query dedup and reserve `UNION` for combining separate\nresult sets.\n\nRule of thumb: dedup one query with `DISTINCT`; combine queries with `UNION`.\n",{"id":82,"difficulty":62,"q":83,"a":84},"type-coercion-union","What happens when column types differ across a UNION?","The database tries to find a **common type** and implicitly casts both sides to it\n(e.g. `int` and `numeric` → `numeric`). If no safe common type exists (text vs date),\nit raises an error.\n\n```sql\n-- int + numeric unify to numeric; fine\nSELECT 1 AS n UNION ALL SELECT 2.5;\n\n-- text + date: cast explicitly to avoid surprises\u002Ferrors\nSELECT created_at::text FROM a UNION ALL SELECT label FROM b;\n```\n\nImplicit coercion can also change precision\u002Fformatting unexpectedly, so cast\nexplicitly when the types aren't obviously compatible.\n\nRule of thumb: cast mismatched columns explicitly so the unified type is intentional.\n",15,null,{"description":11},"SQL set operation interview questions — UNION vs UNION ALL, INTERSECT, EXCEPT, column compatibility rules, deduplication cost and dialect differences.","sql\u002Fbasics\u002Fset-operations","Query Basics","basics","2026-06-20","DS1hmRt82KqRfZsGCop5-Jpe-0c6XL0qn_l2POiZR3I",[95,99,102,106,110],{"subtopic":96,"path":97,"order":98},"Joins","\u002Fsql\u002Fbasics\u002Fjoins",1,{"subtopic":100,"path":101,"order":12},"SELECT & WHERE","\u002Fsql\u002Fbasics\u002Fselect-where",{"subtopic":103,"path":104,"order":105},"Sorting & Limiting","\u002Fsql\u002Fbasics\u002Fsorting-limiting",3,{"subtopic":107,"path":108,"order":109},"Aggregation & GROUP BY","\u002Fsql\u002Fbasics\u002Faggregation",4,{"subtopic":6,"path":21,"order":20},{"path":112,"title":113},"\u002Fblog\u002Fsql-set-operations-union-intersect-except","SQL Set Operations — UNION, INTERSECT, and EXCEPT Explained",1782244106900]