[{"data":1,"prerenderedAt":960},["ShallowReactive",2],{"blog-\u002Fblog\u002Fsql-subqueries-correlated-scalar":3},{"id":4,"title":5,"body":6,"description":946,"difficulty":947,"extension":948,"framework":949,"frameworkSlug":54,"meta":950,"navigation":280,"order":62,"path":951,"qaPath":952,"seo":953,"stem":954,"subtopic":955,"topic":956,"topicSlug":957,"updated":958,"__hash__":959},"blog\u002Fblog\u002Fsql-subqueries-correlated-scalar.md","SQL Subqueries — Scalar, Correlated, and Derived Table Patterns",{"type":7,"value":8,"toc":936},"minimark",[9,14,28,32,49,173,190,194,346,350,356,459,463,469,649,662,666,676,829,835,839,899,902,906,932],[10,11,13],"h2",{"id":12},"what-is-a-subquery","What is a subquery?",[15,16,17,18,22,23,27],"p",{},"A ",[19,20,21],"strong",{},"subquery"," is a ",[24,25,26],"code",{},"SELECT"," statement nested inside another SQL statement. The\nouter query treats the subquery's result as a value, a list, or a temporary\ntable. Subqueries let you express multi-step logic in a single statement — find\nthe highest order value, then fetch the order; find all customers who bought\nproduct X, then count their other purchases.",[10,29,31],{"id":30},"scalar-subqueries-a-single-value","Scalar subqueries — a single value",[15,33,17,34,37,38,40,41,44,45,48],{},[19,35,36],{},"scalar subquery"," returns exactly one row and one column. It can appear\nanywhere an expression is valid: ",[24,39,26],{},", ",[24,42,43],{},"WHERE",", or ",[24,46,47],{},"HAVING",".",[50,51,56],"pre",{"className":52,"code":53,"language":54,"meta":55,"style":55},"language-sql shiki shiki-themes github-light github-dark","-- Show each order with the company-wide average for comparison\nSELECT\n    id,\n    customer_id,\n    total_amount,\n    (SELECT AVG(total_amount) FROM orders) AS company_avg,\n    total_amount - (SELECT AVG(total_amount) FROM orders) AS vs_avg\nFROM orders\nWHERE created_at >= '2026-01-01';\n","sql","",[24,57,58,67,74,81,87,93,120,147,155],{"__ignoreMap":55},[59,60,63],"span",{"class":61,"line":62},"line",1,[59,64,66],{"class":65},"sJ8bj","-- Show each order with the company-wide average for comparison\n",[59,68,70],{"class":61,"line":69},2,[59,71,73],{"class":72},"szBVR","SELECT\n",[59,75,77],{"class":61,"line":76},3,[59,78,80],{"class":79},"sVt8B","    id,\n",[59,82,84],{"class":61,"line":83},4,[59,85,86],{"class":79},"    customer_id,\n",[59,88,90],{"class":61,"line":89},5,[59,91,92],{"class":79},"    total_amount,\n",[59,94,96,99,101,105,108,111,114,117],{"class":61,"line":95},6,[59,97,98],{"class":79},"    (",[59,100,26],{"class":72},[59,102,104],{"class":103},"sj4cs"," AVG",[59,106,107],{"class":79},"(total_amount) ",[59,109,110],{"class":72},"FROM",[59,112,113],{"class":79}," orders) ",[59,115,116],{"class":72},"AS",[59,118,119],{"class":79}," company_avg,\n",[59,121,123,126,129,132,134,136,138,140,142,144],{"class":61,"line":122},7,[59,124,125],{"class":79},"    total_amount ",[59,127,128],{"class":72},"-",[59,130,131],{"class":79}," (",[59,133,26],{"class":72},[59,135,104],{"class":103},[59,137,107],{"class":79},[59,139,110],{"class":72},[59,141,113],{"class":79},[59,143,116],{"class":72},[59,145,146],{"class":79}," vs_avg\n",[59,148,150,152],{"class":61,"line":149},8,[59,151,110],{"class":72},[59,153,154],{"class":79}," orders\n",[59,156,158,160,163,166,170],{"class":61,"line":157},9,[59,159,43],{"class":72},[59,161,162],{"class":79}," created_at ",[59,164,165],{"class":72},">=",[59,167,169],{"class":168},"sZZnC"," '2026-01-01'",[59,171,172],{"class":79},";\n",[15,174,175,176,40,179,40,182,185,186,189],{},"If a scalar subquery returns more than one row, the database raises an error.\nUse aggregate functions (",[24,177,178],{},"MAX",[24,180,181],{},"AVG",[24,183,184],{},"COUNT",") or ",[24,187,188],{},"LIMIT 1"," to guarantee a\nsingle result.",[10,191,193],{"id":192},"subqueries-in-where-filtering-by-a-derived-value","Subqueries in WHERE — filtering by a derived value",[50,195,197],{"className":52,"code":196,"language":54,"meta":55,"style":55},"-- Orders larger than the customer's own average order value\nSELECT id, customer_id, total_amount\nFROM orders o\nWHERE total_amount > (\n    SELECT AVG(total_amount)\n    FROM   orders\n    WHERE  customer_id = o.customer_id  -- correlated: references outer query\n);\n\n-- Most recent order for each customer (alternative to window function)\nSELECT * FROM orders\nWHERE id IN (\n    SELECT MAX(id)\n    FROM   orders\n    GROUP  BY customer_id\n);\n",[24,198,199,204,211,218,231,241,249,271,276,282,288,301,314,325,332,341],{"__ignoreMap":55},[59,200,201],{"class":61,"line":62},[59,202,203],{"class":65},"-- Orders larger than the customer's own average order value\n",[59,205,206,208],{"class":61,"line":69},[59,207,26],{"class":72},[59,209,210],{"class":79}," id, customer_id, total_amount\n",[59,212,213,215],{"class":61,"line":76},[59,214,110],{"class":72},[59,216,217],{"class":79}," orders o\n",[59,219,220,222,225,228],{"class":61,"line":83},[59,221,43],{"class":72},[59,223,224],{"class":79}," total_amount ",[59,226,227],{"class":72},">",[59,229,230],{"class":79}," (\n",[59,232,233,236,238],{"class":61,"line":89},[59,234,235],{"class":72},"    SELECT",[59,237,104],{"class":103},[59,239,240],{"class":79},"(total_amount)\n",[59,242,243,246],{"class":61,"line":95},[59,244,245],{"class":72},"    FROM",[59,247,248],{"class":79},"   orders\n",[59,250,251,254,257,260,263,265,268],{"class":61,"line":122},[59,252,253],{"class":72},"    WHERE",[59,255,256],{"class":79},"  customer_id ",[59,258,259],{"class":72},"=",[59,261,262],{"class":103}," o",[59,264,48],{"class":79},[59,266,267],{"class":103},"customer_id",[59,269,270],{"class":65},"  -- correlated: references outer query\n",[59,272,273],{"class":61,"line":149},[59,274,275],{"class":79},");\n",[59,277,278],{"class":61,"line":157},[59,279,281],{"emptyLinePlaceholder":280},true,"\n",[59,283,285],{"class":61,"line":284},10,[59,286,287],{"class":65},"-- Most recent order for each customer (alternative to window function)\n",[59,289,291,293,296,299],{"class":61,"line":290},11,[59,292,26],{"class":72},[59,294,295],{"class":72}," *",[59,297,298],{"class":72}," FROM",[59,300,154],{"class":79},[59,302,304,306,309,312],{"class":61,"line":303},12,[59,305,43],{"class":72},[59,307,308],{"class":79}," id ",[59,310,311],{"class":72},"IN",[59,313,230],{"class":79},[59,315,317,319,322],{"class":61,"line":316},13,[59,318,235],{"class":72},[59,320,321],{"class":103}," MAX",[59,323,324],{"class":79},"(id)\n",[59,326,328,330],{"class":61,"line":327},14,[59,329,245],{"class":72},[59,331,248],{"class":79},[59,333,335,338],{"class":61,"line":334},15,[59,336,337],{"class":72},"    GROUP  BY",[59,339,340],{"class":79}," customer_id\n",[59,342,344],{"class":61,"line":343},16,[59,345,275],{"class":79},[10,347,349],{"id":348},"correlated-subqueries-referencing-the-outer-row","Correlated subqueries — referencing the outer row",[15,351,17,352,355],{},[19,353,354],{},"correlated subquery"," refers to a column from the outer query. It is\nre-executed for each row of the outer query — making it logically equivalent\nto a nested loop. This is powerful but can be slow on large tables; use an\nindex on the correlated column or rewrite with a JOIN.",[50,357,359],{"className":52,"code":358,"language":54,"meta":55,"style":55},"-- Customers whose most recent order was a refund\nSELECT c.id, c.email\nFROM customers c\nWHERE (\n    SELECT status\n    FROM   orders\n    WHERE  customer_id = c.id\n    ORDER  BY created_at DESC\n    LIMIT  1\n) = 'refunded';\n",[24,360,361,366,388,395,401,408,414,429,439,447],{"__ignoreMap":55},[59,362,363],{"class":61,"line":62},[59,364,365],{"class":65},"-- Customers whose most recent order was a refund\n",[59,367,368,370,373,375,378,380,383,385],{"class":61,"line":69},[59,369,26],{"class":72},[59,371,372],{"class":103}," c",[59,374,48],{"class":79},[59,376,377],{"class":103},"id",[59,379,40],{"class":79},[59,381,382],{"class":103},"c",[59,384,48],{"class":79},[59,386,387],{"class":103},"email\n",[59,389,390,392],{"class":61,"line":76},[59,391,110],{"class":72},[59,393,394],{"class":79}," customers c\n",[59,396,397,399],{"class":61,"line":83},[59,398,43],{"class":72},[59,400,230],{"class":79},[59,402,403,405],{"class":61,"line":89},[59,404,235],{"class":72},[59,406,407],{"class":72}," status\n",[59,409,410,412],{"class":61,"line":95},[59,411,245],{"class":72},[59,413,248],{"class":79},[59,415,416,418,420,422,424,426],{"class":61,"line":122},[59,417,253],{"class":72},[59,419,256],{"class":79},[59,421,259],{"class":72},[59,423,372],{"class":103},[59,425,48],{"class":79},[59,427,428],{"class":103},"id\n",[59,430,431,434,436],{"class":61,"line":149},[59,432,433],{"class":72},"    ORDER  BY",[59,435,162],{"class":79},[59,437,438],{"class":72},"DESC\n",[59,440,441,444],{"class":61,"line":157},[59,442,443],{"class":72},"    LIMIT",[59,445,446],{"class":103},"  1\n",[59,448,449,452,454,457],{"class":61,"line":284},[59,450,451],{"class":79},") ",[59,453,259],{"class":72},[59,455,456],{"class":168}," 'refunded'",[59,458,172],{"class":79},[10,460,462],{"id":461},"exists-and-not-exists-the-null-safe-existence-test","EXISTS and NOT EXISTS — the NULL-safe existence test",[15,464,465,468],{},[24,466,467],{},"EXISTS"," returns TRUE as soon as the subquery finds one matching row — it\nshort-circuits and is efficient with an index on the join column.",[50,470,472],{"className":52,"code":471,"language":54,"meta":55,"style":55},"-- Customers who have placed at least one order over £200\nSELECT c.id, c.email\nFROM customers c\nWHERE EXISTS (\n    SELECT 1\n    FROM   orders o\n    WHERE  o.customer_id = c.id\n      AND  o.total_amount > 200\n);\n\n-- Products never added to any wishlist (anti-join via NOT EXISTS)\nSELECT p.id, p.product_name\nFROM products p\nWHERE NOT EXISTS (\n    SELECT 1 FROM wishlist_items w WHERE w.product_id = p.id\n);\n",[24,473,474,479,497,503,512,519,526,546,564,568,572,577,597,604,615,645],{"__ignoreMap":55},[59,475,476],{"class":61,"line":62},[59,477,478],{"class":65},"-- Customers who have placed at least one order over £200\n",[59,480,481,483,485,487,489,491,493,495],{"class":61,"line":69},[59,482,26],{"class":72},[59,484,372],{"class":103},[59,486,48],{"class":79},[59,488,377],{"class":103},[59,490,40],{"class":79},[59,492,382],{"class":103},[59,494,48],{"class":79},[59,496,387],{"class":103},[59,498,499,501],{"class":61,"line":76},[59,500,110],{"class":72},[59,502,394],{"class":79},[59,504,505,507,510],{"class":61,"line":83},[59,506,43],{"class":72},[59,508,509],{"class":72}," EXISTS",[59,511,230],{"class":79},[59,513,514,516],{"class":61,"line":89},[59,515,235],{"class":72},[59,517,518],{"class":103}," 1\n",[59,520,521,523],{"class":61,"line":95},[59,522,245],{"class":72},[59,524,525],{"class":79},"   orders o\n",[59,527,528,530,533,535,537,540,542,544],{"class":61,"line":122},[59,529,253],{"class":72},[59,531,532],{"class":103},"  o",[59,534,48],{"class":79},[59,536,267],{"class":103},[59,538,539],{"class":72}," =",[59,541,372],{"class":103},[59,543,48],{"class":79},[59,545,428],{"class":103},[59,547,548,551,553,555,558,561],{"class":61,"line":149},[59,549,550],{"class":72},"      AND",[59,552,532],{"class":103},[59,554,48],{"class":79},[59,556,557],{"class":103},"total_amount",[59,559,560],{"class":72}," >",[59,562,563],{"class":103}," 200\n",[59,565,566],{"class":61,"line":157},[59,567,275],{"class":79},[59,569,570],{"class":61,"line":284},[59,571,281],{"emptyLinePlaceholder":280},[59,573,574],{"class":61,"line":290},[59,575,576],{"class":65},"-- Products never added to any wishlist (anti-join via NOT EXISTS)\n",[59,578,579,581,584,586,588,590,592,594],{"class":61,"line":303},[59,580,26],{"class":72},[59,582,583],{"class":103}," p",[59,585,48],{"class":79},[59,587,377],{"class":103},[59,589,40],{"class":79},[59,591,15],{"class":103},[59,593,48],{"class":79},[59,595,596],{"class":103},"product_name\n",[59,598,599,601],{"class":61,"line":316},[59,600,110],{"class":72},[59,602,603],{"class":79}," products p\n",[59,605,606,608,611,613],{"class":61,"line":327},[59,607,43],{"class":72},[59,609,610],{"class":72}," NOT",[59,612,509],{"class":72},[59,614,230],{"class":79},[59,616,617,619,622,624,627,629,632,634,637,639,641,643],{"class":61,"line":334},[59,618,235],{"class":72},[59,620,621],{"class":103}," 1",[59,623,298],{"class":72},[59,625,626],{"class":79}," wishlist_items w ",[59,628,43],{"class":72},[59,630,631],{"class":103}," w",[59,633,48],{"class":79},[59,635,636],{"class":103},"product_id",[59,638,539],{"class":72},[59,640,583],{"class":103},[59,642,48],{"class":79},[59,644,428],{"class":103},[59,646,647],{"class":61,"line":343},[59,648,275],{"class":79},[15,650,651,654,655,658,659,661],{},[24,652,653],{},"NOT EXISTS"," handles NULLs correctly. ",[24,656,657],{},"NOT IN"," with a subquery fails silently\nif the subquery returns any NULL — prefer ",[24,660,653],{}," for anti-join patterns.",[10,663,665],{"id":664},"derived-tables-subqueries-in-from","Derived tables — subqueries in FROM",[15,667,668,669,671,672,675],{},"A subquery in ",[24,670,110],{}," creates a ",[19,673,674],{},"derived table"," (also called an inline view).\nThe outer query treats it like a real table and can filter, join, and aggregate\nit.",[50,677,679],{"className":52,"code":678,"language":54,"meta":55,"style":55},"-- Top 5 customers by lifetime value, with their most recent order date\nSELECT ranked.customer_id, ranked.lifetime_value, ranked.last_order\nFROM (\n    SELECT\n        customer_id,\n        SUM(total_amount) AS lifetime_value,\n        MAX(created_at)   AS last_order,\n        RANK() OVER (ORDER BY SUM(total_amount) DESC) AS rnk\n    FROM orders\n    GROUP BY customer_id\n) AS ranked\nWHERE ranked.rnk \u003C= 5;\n",[24,680,681,686,716,722,727,732,744,757,788,794,801,810],{"__ignoreMap":55},[59,682,683],{"class":61,"line":62},[59,684,685],{"class":65},"-- Top 5 customers by lifetime value, with their most recent order date\n",[59,687,688,690,693,695,697,699,702,704,707,709,711,713],{"class":61,"line":69},[59,689,26],{"class":72},[59,691,692],{"class":103}," ranked",[59,694,48],{"class":79},[59,696,267],{"class":103},[59,698,40],{"class":79},[59,700,701],{"class":103},"ranked",[59,703,48],{"class":79},[59,705,706],{"class":103},"lifetime_value",[59,708,40],{"class":79},[59,710,701],{"class":103},[59,712,48],{"class":79},[59,714,715],{"class":103},"last_order\n",[59,717,718,720],{"class":61,"line":76},[59,719,110],{"class":72},[59,721,230],{"class":79},[59,723,724],{"class":61,"line":83},[59,725,726],{"class":72},"    SELECT\n",[59,728,729],{"class":61,"line":89},[59,730,731],{"class":79},"        customer_id,\n",[59,733,734,737,739,741],{"class":61,"line":95},[59,735,736],{"class":103},"        SUM",[59,738,107],{"class":79},[59,740,116],{"class":72},[59,742,743],{"class":79}," lifetime_value,\n",[59,745,746,749,752,754],{"class":61,"line":122},[59,747,748],{"class":103},"        MAX",[59,750,751],{"class":79},"(created_at)   ",[59,753,116],{"class":72},[59,755,756],{"class":79}," last_order,\n",[59,758,759,762,765,768,770,773,776,778,781,783,785],{"class":61,"line":149},[59,760,761],{"class":103},"        RANK",[59,763,764],{"class":79},"() ",[59,766,767],{"class":72},"OVER",[59,769,131],{"class":79},[59,771,772],{"class":72},"ORDER BY",[59,774,775],{"class":103}," SUM",[59,777,107],{"class":79},[59,779,780],{"class":72},"DESC",[59,782,451],{"class":79},[59,784,116],{"class":72},[59,786,787],{"class":79}," rnk\n",[59,789,790,792],{"class":61,"line":157},[59,791,245],{"class":72},[59,793,154],{"class":79},[59,795,796,799],{"class":61,"line":284},[59,797,798],{"class":72},"    GROUP BY",[59,800,340],{"class":79},[59,802,803,805,807],{"class":61,"line":290},[59,804,451],{"class":79},[59,806,116],{"class":72},[59,808,809],{"class":79}," ranked\n",[59,811,812,814,816,818,821,824,827],{"class":61,"line":303},[59,813,43],{"class":72},[59,815,692],{"class":103},[59,817,48],{"class":79},[59,819,820],{"class":103},"rnk",[59,822,823],{"class":72}," \u003C=",[59,825,826],{"class":103}," 5",[59,828,172],{"class":79},[15,830,831,832,834],{},"Derived tables must be given an alias. Every column in the subquery that the\nouter query references must have a name (use ",[24,833,116],{}," if it is a computed column).",[10,836,838],{"id":837},"subquery-vs-join-when-to-use-which","Subquery vs JOIN — when to use which",[840,841,842,855],"table",{},[843,844,845],"thead",{},[846,847,848,852],"tr",{},[849,850,851],"th",{},"Situation",[849,853,854],{},"Prefer",[856,857,858,867,875,883,891],"tbody",{},[846,859,860,864],{},[861,862,863],"td",{},"Need columns from the related table",[861,865,866],{},"JOIN",[846,868,869,872],{},[861,870,871],{},"Just checking existence \u002F absence",[861,873,874],{},"EXISTS \u002F NOT EXISTS",[846,876,877,880],{},[861,878,879],{},"Need aggregate from the related table per outer row",[861,881,882],{},"Correlated subquery or window function",[846,884,885,888],{},[861,886,887],{},"Pre-aggregating before joining",[861,889,890],{},"Derived table or CTE",[846,892,893,896],{},[861,894,895],{},"Filtering by a single derived value",[861,897,898],{},"Scalar subquery",[15,900,901],{},"Correlated subqueries that run once per outer row are fine for small tables\nbut can be expensive at scale. For large datasets, rewrite as a JOIN with\npre-aggregation or use a window function.",[10,903,905],{"id":904},"recap","Recap",[15,907,908,909,912,913,916,917,924,925,928,929,931],{},"Subqueries let you nest queries to express multi-step logic. ",[19,910,911],{},"Scalar\nsubqueries"," return one value and plug into any expression context. ",[19,914,915],{},"Correlated\nsubqueries"," reference the outer row — powerful but potentially slow; ensure the\ncorrelated column is indexed. ",[19,918,919,921,922],{},[24,920,467],{}," \u002F ",[24,923,653],{}," are the safest and\nmost efficient way to test membership and exclusion. ",[19,926,927],{},"Derived tables"," in ",[24,930,110],{},"\nact as named intermediate result sets and are the stepping stone to CTEs.",[933,934,935],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":55,"searchDepth":69,"depth":69,"links":937},[938,939,940,941,942,943,944,945],{"id":12,"depth":69,"text":13},{"id":30,"depth":69,"text":31},{"id":192,"depth":69,"text":193},{"id":348,"depth":69,"text":349},{"id":461,"depth":69,"text":462},{"id":664,"depth":69,"text":665},{"id":837,"depth":69,"text":838},{"id":904,"depth":69,"text":905},"SQL subquery types explained with real examples — scalar subqueries, correlated subqueries, derived tables, EXISTS, and when to use each.","medium","md","SQL",{},"\u002Fblog\u002Fsql-subqueries-correlated-scalar","\u002Fsql\u002Fsubqueries\u002Fsubqueries",{"title":5,"description":946},"blog\u002Fsql-subqueries-correlated-scalar","Subqueries","Subqueries & CTEs","subqueries","2026-06-20","V1N8o4kbOT2qc8E5Doyz7a6fHWCqXj7HAYE4JInA2tc",1782244088299]