[{"data":1,"prerenderedAt":1079},["ShallowReactive",2],{"blog-\u002Fblog\u002Fsql-window-functions-vs-group-by":3},{"id":4,"title":5,"body":6,"description":1065,"difficulty":1066,"extension":1067,"framework":1068,"frameworkSlug":253,"meta":1069,"navigation":1070,"order":268,"path":1071,"qaPath":768,"seo":1072,"stem":1073,"subtopic":1074,"topic":1075,"topicSlug":1076,"updated":1077,"__hash__":1078},"blog\u002Fblog\u002Fsql-window-functions-vs-group-by.md","SQL Window Functions vs GROUP BY — What the Difference Is and When to Use Each",{"type":7,"value":8,"toc":1048},"minimark",[9,14,31,35,48,52,233,239,248,343,356,361,428,439,443,459,551,560,564,569,653,657,748,762,770,774,820,824,901,905,915,983,999,1003,1011,1019,1023,1044],[10,11,13],"h2",{"id":12},"the-most-common-aggregation-confusion-in-sql-interviews","The most common aggregation confusion in SQL interviews",[15,16,17,18,22,23,25,26,30],"p",{},"Interviewers love asking: \"Show me each employee's salary alongside the average salary for\ntheir department.\" Most candidates reach for ",[19,20,21],"code",{},"GROUP BY"," and immediately hit a wall — you\ncan't do it with ",[19,24,21],{}," alone. The answer is a ",[27,28,29],"strong",{},"window function",", and understanding\nexactly why reveals the core difference between the two approaches.",[10,32,34],{"id":33},"the-fundamental-difference-in-one-sentence","The fundamental difference in one sentence",[15,36,37,39,40,43,44,47],{},[19,38,21],{}," ",[27,41,42],{},"collapses rows"," — output has fewer rows than input. A window function\n",[27,45,46],{},"annotates rows"," — output has the same number of rows as input, with an extra computed\ncolumn.",[10,49,51],{"id":50},"quick-reference-comparison","Quick-reference comparison",[53,54,55,76],"table",{},[56,57,58],"thead",{},[59,60,61,64,69],"tr",{},[62,63],"th",{},[62,65,66,68],{},[19,67,21],{}," aggregate",[62,70,71,72,75],{},"Window function (",[19,73,74],{},"OVER",")",[77,78,79,93,106,119,135,148,168,190,208,220],"tbody",{},[59,80,81,87,90],{},[82,83,84],"td",{},[27,85,86],{},"Output rows",[82,88,89],{},"One per group",[82,91,92],{},"Same count as input",[59,94,95,100,103],{},[82,96,97],{},[27,98,99],{},"Detail columns",[82,101,102],{},"Only grouping columns",[82,104,105],{},"All original columns kept",[59,107,108,113,116],{},[82,109,110],{},[27,111,112],{},"Can compare row to group?",[82,114,115],{},"No — detail is gone",[82,117,118],{},"Yes — both values on each row",[59,120,121,129,132],{},[82,122,123],{},[27,124,125,126,128],{},"Requires ",[19,127,74],{}," clause?",[82,130,131],{},"No",[82,133,134],{},"Yes",[59,136,137,144,146],{},[82,138,139],{},[27,140,125,141,143],{},[19,142,21],{},"?",[82,145,134],{},[82,147,131],{},[59,149,150,158,161],{},[82,151,152],{},[27,153,154,155,143],{},"Can use ",[19,156,157],{},"HAVING",[82,159,160],{},"Yes — filter after aggregation",[82,162,163,164,167],{},"No — use ",[19,165,166],{},"WHERE"," in a subquery\u002FCTE",[59,169,170,175,177],{},[82,171,172],{},[27,173,174],{},"Ranking support?",[82,176,131],{},[82,178,179,180,183,184,183,187],{},"Yes — ",[19,181,182],{},"ROW_NUMBER",", ",[19,185,186],{},"RANK",[19,188,189],{},"DENSE_RANK",[59,191,192,197,199],{},[82,193,194],{},[27,195,196],{},"Running totals?",[82,198,131],{},[82,200,201,202,205,206],{},"Yes — with ",[19,203,204],{},"ORDER BY"," in ",[19,207,74],{},[59,209,210,215,217],{},[82,211,212],{},[27,213,214],{},"Moving averages?",[82,216,131],{},[82,218,219],{},"Yes — with frame clause",[59,221,222,227,230],{},[82,223,224],{},[27,225,226],{},"Best for",[82,228,229],{},"Summary reports, aggregated output",[82,231,232],{},"Row-level analysis with group context",[10,234,236,238],{"id":235},"group-by-collapsing-rows-into-summaries",[19,237,21],{}," — collapsing rows into summaries",[15,240,241,243,244,247],{},[19,242,21],{}," is the right tool when the output should be ",[27,245,246],{},"one row per group"," — you want\nthe summary, not the detail.",[249,250,255],"pre",{"className":251,"code":252,"language":253,"meta":254,"style":254},"language-sql shiki shiki-themes github-light github-dark","-- One row per department — detail rows are gone\nSELECT   dept_id,\n         COUNT(*)       AS headcount,\n         AVG(salary)    AS avg_salary,\n         MAX(salary)    AS max_salary\nFROM     employees\nGROUP BY dept_id;\n","sql","",[19,256,257,266,277,299,313,326,335],{"__ignoreMap":254},[258,259,262],"span",{"class":260,"line":261},"line",1,[258,263,265],{"class":264},"sJ8bj","-- One row per department — detail rows are gone\n",[258,267,269,273],{"class":260,"line":268},2,[258,270,272],{"class":271},"szBVR","SELECT",[258,274,276],{"class":275},"sVt8B","   dept_id,\n",[258,278,280,284,287,290,293,296],{"class":260,"line":279},3,[258,281,283],{"class":282},"sj4cs","         COUNT",[258,285,286],{"class":275},"(",[258,288,289],{"class":271},"*",[258,291,292],{"class":275},")       ",[258,294,295],{"class":271},"AS",[258,297,298],{"class":275}," headcount,\n",[258,300,302,305,308,310],{"class":260,"line":301},4,[258,303,304],{"class":282},"         AVG",[258,306,307],{"class":275},"(salary)    ",[258,309,295],{"class":271},[258,311,312],{"class":275}," avg_salary,\n",[258,314,316,319,321,323],{"class":260,"line":315},5,[258,317,318],{"class":282},"         MAX",[258,320,307],{"class":275},[258,322,295],{"class":271},[258,324,325],{"class":275}," max_salary\n",[258,327,329,332],{"class":260,"line":328},6,[258,330,331],{"class":271},"FROM",[258,333,334],{"class":275},"     employees\n",[258,336,338,340],{"class":260,"line":337},7,[258,339,21],{"class":271},[258,341,342],{"class":275}," dept_id;\n",[15,344,345,346,348,349,351,352,355],{},"You can only ",[19,347,272],{}," columns that are either in ",[19,350,21],{}," or wrapped in an aggregate\nfunction. Trying to select ",[19,353,354],{},"name"," here raises an error — the engine doesn't know which\nemployee's name to show per group.",[15,357,358,360],{},[19,359,157],{}," filters on the aggregated result (after grouping):",[249,362,364],{"className":251,"code":363,"language":253,"meta":254,"style":254},"-- Only show departments with more than 10 employees\nSELECT   dept_id, COUNT(*) AS headcount\nFROM     employees\nGROUP BY dept_id\nHAVING   COUNT(*) > 10;\n",[19,365,366,371,393,399,406],{"__ignoreMap":254},[258,367,368],{"class":260,"line":261},[258,369,370],{"class":264},"-- Only show departments with more than 10 employees\n",[258,372,373,375,378,381,383,385,388,390],{"class":260,"line":268},[258,374,272],{"class":271},[258,376,377],{"class":275},"   dept_id, ",[258,379,380],{"class":282},"COUNT",[258,382,286],{"class":275},[258,384,289],{"class":271},[258,386,387],{"class":275},") ",[258,389,295],{"class":271},[258,391,392],{"class":275}," headcount\n",[258,394,395,397],{"class":260,"line":279},[258,396,331],{"class":271},[258,398,334],{"class":275},[258,400,401,403],{"class":260,"line":301},[258,402,21],{"class":271},[258,404,405],{"class":275}," dept_id\n",[258,407,408,410,413,415,417,419,422,425],{"class":260,"line":315},[258,409,157],{"class":271},[258,411,412],{"class":282},"   COUNT",[258,414,286],{"class":275},[258,416,289],{"class":271},[258,418,387],{"class":275},[258,420,421],{"class":271},">",[258,423,424],{"class":282}," 10",[258,426,427],{"class":275},";\n",[429,430,431],"blockquote",{},[15,432,433,434],{},"Deep dive: ",[435,436,438],"a",{"href":437},"\u002Fsql\u002Fbasics\u002Faggregation","Aggregation & GROUP BY interview questions",[10,440,442],{"id":441},"window-functions-keeping-the-detail","Window functions — keeping the detail",[15,444,445,446,449,450,452,453,455,456,458],{},"A window function adds a computed value alongside each row. ",[19,447,448],{},"PARTITION BY"," divides the\nwindow into groups (like ",[19,451,21],{},"), but ",[19,454,204],{}," inside ",[19,457,74],{}," doesn't remove rows —\nit just establishes row order for running calculations.",[249,460,462],{"className":251,"code":461,"language":253,"meta":254,"style":254},"-- Every employee row is kept — salary AND the department average side by side\nSELECT name,\n       dept_id,\n       salary,\n       AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg,\n       salary - AVG(salary) OVER (PARTITION BY dept_id) AS diff_from_avg\nFROM   employees;\n",[19,463,464,469,479,484,489,516,544],{"__ignoreMap":254},[258,465,466],{"class":260,"line":261},[258,467,468],{"class":264},"-- Every employee row is kept — salary AND the department average side by side\n",[258,470,471,473,476],{"class":260,"line":268},[258,472,272],{"class":271},[258,474,475],{"class":271}," name",[258,477,478],{"class":275},",\n",[258,480,481],{"class":260,"line":279},[258,482,483],{"class":275},"       dept_id,\n",[258,485,486],{"class":260,"line":301},[258,487,488],{"class":275},"       salary,\n",[258,490,491,494,497,499,502,505,508,511,513],{"class":260,"line":315},[258,492,493],{"class":282},"       AVG",[258,495,496],{"class":275},"(salary) ",[258,498,74],{"class":271},[258,500,501],{"class":275}," (",[258,503,504],{"class":271},"PARTITION",[258,506,507],{"class":271}," BY",[258,509,510],{"class":275}," dept_id) ",[258,512,295],{"class":271},[258,514,515],{"class":275}," dept_avg,\n",[258,517,518,521,524,527,529,531,533,535,537,539,541],{"class":260,"line":328},[258,519,520],{"class":275},"       salary ",[258,522,523],{"class":271},"-",[258,525,526],{"class":282}," AVG",[258,528,496],{"class":275},[258,530,74],{"class":271},[258,532,501],{"class":275},[258,534,504],{"class":271},[258,536,507],{"class":271},[258,538,510],{"class":275},[258,540,295],{"class":271},[258,542,543],{"class":275}," diff_from_avg\n",[258,545,546,548],{"class":260,"line":337},[258,547,331],{"class":271},[258,549,550],{"class":275},"   employees;\n",[15,552,553,554,559],{},"This query is ",[27,555,556,557],{},"impossible with plain ",[19,558,21],{},". The department average needs grouping,\nbut the individual salary and name need the detail rows. Window functions let you have\nboth at once.",[10,561,563],{"id":562},"queries-only-window-functions-can-answer","Queries only window functions can answer",[565,566,568],"h3",{"id":567},"_1-row-vs-group-comparison","1 — Row vs group comparison",[249,570,572],{"className":251,"code":571,"language":253,"meta":254,"style":254},"-- Who earns above their department average?\nSELECT name, dept_id, salary\nFROM (\n    SELECT name, dept_id, salary,\n           AVG(salary) OVER (PARTITION BY dept_id) AS dept_avg\n    FROM employees\n) t\nWHERE salary > dept_avg;\n",[19,573,574,579,588,595,605,627,635,640],{"__ignoreMap":254},[258,575,576],{"class":260,"line":261},[258,577,578],{"class":264},"-- Who earns above their department average?\n",[258,580,581,583,585],{"class":260,"line":268},[258,582,272],{"class":271},[258,584,475],{"class":271},[258,586,587],{"class":275},", dept_id, salary\n",[258,589,590,592],{"class":260,"line":279},[258,591,331],{"class":271},[258,593,594],{"class":275}," (\n",[258,596,597,600,602],{"class":260,"line":301},[258,598,599],{"class":271},"    SELECT",[258,601,475],{"class":271},[258,603,604],{"class":275},", dept_id, salary,\n",[258,606,607,610,612,614,616,618,620,622,624],{"class":260,"line":315},[258,608,609],{"class":282},"           AVG",[258,611,496],{"class":275},[258,613,74],{"class":271},[258,615,501],{"class":275},[258,617,504],{"class":271},[258,619,507],{"class":271},[258,621,510],{"class":275},[258,623,295],{"class":271},[258,625,626],{"class":275}," dept_avg\n",[258,628,629,632],{"class":260,"line":328},[258,630,631],{"class":271},"    FROM",[258,633,634],{"class":275}," employees\n",[258,636,637],{"class":260,"line":337},[258,638,639],{"class":275},") t\n",[258,641,643,645,648,650],{"class":260,"line":642},8,[258,644,166],{"class":271},[258,646,647],{"class":275}," salary ",[258,649,421],{"class":271},[258,651,652],{"class":275}," dept_avg;\n",[565,654,656],{"id":655},"_2-ranking-within-a-group","2 — Ranking within a group",[249,658,660],{"className":251,"code":659,"language":253,"meta":254,"style":254},"-- Top earner per department (rank = 1)\nSELECT name, dept_id, salary, rank\nFROM (\n    SELECT name, dept_id, salary,\n           RANK() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rank\n    FROM employees\n) t\nWHERE rank = 1;\n",[19,661,662,667,676,682,690,723,729,733],{"__ignoreMap":254},[258,663,664],{"class":260,"line":261},[258,665,666],{"class":264},"-- Top earner per department (rank = 1)\n",[258,668,669,671,673],{"class":260,"line":268},[258,670,272],{"class":271},[258,672,475],{"class":271},[258,674,675],{"class":275},", dept_id, salary, rank\n",[258,677,678,680],{"class":260,"line":279},[258,679,331],{"class":271},[258,681,594],{"class":275},[258,683,684,686,688],{"class":260,"line":301},[258,685,599],{"class":271},[258,687,475],{"class":271},[258,689,604],{"class":275},[258,691,692,695,698,700,702,704,706,709,711,713,716,718,720],{"class":260,"line":315},[258,693,694],{"class":282},"           RANK",[258,696,697],{"class":275},"() ",[258,699,74],{"class":271},[258,701,501],{"class":275},[258,703,504],{"class":271},[258,705,507],{"class":271},[258,707,708],{"class":275}," dept_id ",[258,710,204],{"class":271},[258,712,647],{"class":275},[258,714,715],{"class":271},"DESC",[258,717,387],{"class":275},[258,719,295],{"class":271},[258,721,722],{"class":275}," rank\n",[258,724,725,727],{"class":260,"line":328},[258,726,631],{"class":271},[258,728,634],{"class":275},[258,730,731],{"class":260,"line":337},[258,732,639],{"class":275},[258,734,735,737,740,743,746],{"class":260,"line":642},[258,736,166],{"class":271},[258,738,739],{"class":275}," rank ",[258,741,742],{"class":271},"=",[258,744,745],{"class":282}," 1",[258,747,427],{"class":275},[15,749,750,752,753,757,758,761],{},[19,751,21],{}," can find the max salary per department, but it can't tell you ",[754,755,756],"em",{},"who"," earned it\nwithout a second join. ",[19,759,760],{},"RANK()"," does it in one pass.",[429,763,764],{},[15,765,433,766],{},[435,767,769],{"href":768},"\u002Fsql\u002Fwindow-functions\u002Fwindow-basics","Window Function Basics interview questions",[565,771,773],{"id":772},"_3-running-totals","3 — Running totals",[249,775,777],{"className":251,"code":776,"language":253,"meta":254,"style":254},"-- Cumulative salary spend, ordered by hire date\nSELECT name, hire_date, salary,\n       SUM(salary) OVER (ORDER BY hire_date) AS running_total\nFROM   employees;\n",[19,778,779,784,793,814],{"__ignoreMap":254},[258,780,781],{"class":260,"line":261},[258,782,783],{"class":264},"-- Cumulative salary spend, ordered by hire date\n",[258,785,786,788,790],{"class":260,"line":268},[258,787,272],{"class":271},[258,789,475],{"class":271},[258,791,792],{"class":275},", hire_date, salary,\n",[258,794,795,798,800,802,804,806,809,811],{"class":260,"line":279},[258,796,797],{"class":282},"       SUM",[258,799,496],{"class":275},[258,801,74],{"class":271},[258,803,501],{"class":275},[258,805,204],{"class":271},[258,807,808],{"class":275}," hire_date) ",[258,810,295],{"class":271},[258,812,813],{"class":275}," running_total\n",[258,815,816,818],{"class":260,"line":301},[258,817,331],{"class":271},[258,819,550],{"class":275},[565,821,823],{"id":822},"_4-row-over-row-comparisons-lag-lead","4 — Row-over-row comparisons (LAG \u002F LEAD)",[249,825,827],{"className":251,"code":826,"language":253,"meta":254,"style":254},"-- Each employee's salary compared to the next hire in their department\nSELECT name, hire_date, salary,\n       LAG(salary)  OVER (PARTITION BY dept_id ORDER BY hire_date) AS prev_hire_salary,\n       LEAD(salary) OVER (PARTITION BY dept_id ORDER BY hire_date) AS next_hire_salary\nFROM   employees;\n",[19,828,829,834,842,869,895],{"__ignoreMap":254},[258,830,831],{"class":260,"line":261},[258,832,833],{"class":264},"-- Each employee's salary compared to the next hire in their department\n",[258,835,836,838,840],{"class":260,"line":268},[258,837,272],{"class":271},[258,839,475],{"class":271},[258,841,792],{"class":275},[258,843,844,847,850,852,854,856,858,860,862,864,866],{"class":260,"line":279},[258,845,846],{"class":282},"       LAG",[258,848,849],{"class":275},"(salary)  ",[258,851,74],{"class":271},[258,853,501],{"class":275},[258,855,504],{"class":271},[258,857,507],{"class":271},[258,859,708],{"class":275},[258,861,204],{"class":271},[258,863,808],{"class":275},[258,865,295],{"class":271},[258,867,868],{"class":275}," prev_hire_salary,\n",[258,870,871,874,876,878,880,882,884,886,888,890,892],{"class":260,"line":301},[258,872,873],{"class":282},"       LEAD",[258,875,496],{"class":275},[258,877,74],{"class":271},[258,879,501],{"class":275},[258,881,504],{"class":271},[258,883,507],{"class":271},[258,885,708],{"class":275},[258,887,204],{"class":271},[258,889,808],{"class":275},[258,891,295],{"class":271},[258,893,894],{"class":275}," next_hire_salary\n",[258,896,897,899],{"class":260,"line":315},[258,898,331],{"class":271},[258,900,550],{"class":275},[10,902,904],{"id":903},"can-you-combine-both-in-one-query","Can you combine both in one query?",[15,906,907,908,910,911,914],{},"Yes. ",[19,909,21],{}," and window functions can coexist — the window function sees the ",[754,912,913],{},"grouped","\nrows:",[249,916,918],{"className":251,"code":917,"language":253,"meta":254,"style":254},"-- Aggregate first, then rank the summaries\nSELECT dept_id,\n       SUM(salary) AS total_spend,\n       RANK() OVER (ORDER BY SUM(salary) DESC) AS spend_rank\nFROM   employees\nGROUP BY dept_id;\n",[19,919,920,925,932,943,970,977],{"__ignoreMap":254},[258,921,922],{"class":260,"line":261},[258,923,924],{"class":264},"-- Aggregate first, then rank the summaries\n",[258,926,927,929],{"class":260,"line":268},[258,928,272],{"class":271},[258,930,931],{"class":275}," dept_id,\n",[258,933,934,936,938,940],{"class":260,"line":279},[258,935,797],{"class":282},[258,937,496],{"class":275},[258,939,295],{"class":271},[258,941,942],{"class":275}," total_spend,\n",[258,944,945,948,950,952,954,956,959,961,963,965,967],{"class":260,"line":301},[258,946,947],{"class":282},"       RANK",[258,949,697],{"class":275},[258,951,74],{"class":271},[258,953,501],{"class":275},[258,955,204],{"class":271},[258,957,958],{"class":282}," SUM",[258,960,496],{"class":275},[258,962,715],{"class":271},[258,964,387],{"class":275},[258,966,295],{"class":271},[258,968,969],{"class":275}," spend_rank\n",[258,971,972,974],{"class":260,"line":315},[258,973,331],{"class":271},[258,975,976],{"class":275},"   employees\n",[258,978,979,981],{"class":260,"line":328},[258,980,21],{"class":271},[258,982,342],{"class":275},[15,984,985,986,39,989,991,992,994,995,998],{},"Window functions are evaluated ",[27,987,988],{},"after",[19,990,21],{}," and ",[19,993,157],{},", so ",[19,996,997],{},"SUM(salary)"," here\noperates on the already-grouped rows.",[10,1000,1002],{"id":1001},"the-decision-rule","The decision rule",[249,1004,1009],{"className":1005,"code":1007,"language":1008},[1006],"language-text","Do I want fewer rows than I started with — one row per group?\n└── Yes → GROUP BY\n\nDo I want all rows, but with a per-group aggregate attached?\n└── Yes → window function with PARTITION BY\n\nDo I need ranking, running totals, or row-over-row comparisons?\n└── Yes → window function (RANK\u002FROW_NUMBER, ORDER BY inside OVER, LAG\u002FLEAD)\n","text",[19,1010,1007],{"__ignoreMap":254},[15,1012,1013,1014],{},"A useful mental model: ",[27,1015,1016,1018],{},[19,1017,21],{}," answers \"what is the summary of each group?\" while\nwindow functions answer \"how does each row relate to its group?\"",[10,1020,1022],{"id":1021},"recap","Recap",[15,1024,1025,1027,1028,1031,1032,1034,1035,1040,1041,1043],{},[19,1026,21],{}," is the right tool when you want a ",[27,1029,1030],{},"summary with one row per group"," —\n",[19,1033,157],{}," filters those groups, and detail columns are unavailable. A ",[27,1036,1037,1038],{},"window function\nwith ",[19,1039,74],{}," keeps every row and attaches a group-level aggregate alongside it, enabling\ncomparisons between a row and its group, rankings, running totals, and moving averages —\nqueries that are impossible or require multiple self-joins without them. When you need both\n(rank the summaries themselves), ",[19,1042,21],{}," runs first and the window function operates\non the grouped result.",[1045,1046,1047],"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 .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":254,"searchDepth":268,"depth":268,"links":1049},[1050,1051,1052,1053,1055,1056,1062,1063,1064],{"id":12,"depth":268,"text":13},{"id":33,"depth":268,"text":34},{"id":50,"depth":268,"text":51},{"id":235,"depth":268,"text":1054},"GROUP BY — collapsing rows into summaries",{"id":441,"depth":268,"text":442},{"id":562,"depth":268,"text":563,"children":1057},[1058,1059,1060,1061],{"id":567,"depth":279,"text":568},{"id":655,"depth":279,"text":656},{"id":772,"depth":279,"text":773},{"id":822,"depth":279,"text":823},{"id":903,"depth":268,"text":904},{"id":1001,"depth":268,"text":1002},{"id":1021,"depth":268,"text":1022},"SQL window functions vs GROUP BY explained — row preservation, PARTITION BY, the queries each makes possible, and the decision rule for writing clear, correct aggregation SQL.","medium","md","SQL",{},true,"\u002Fblog\u002Fsql-window-functions-vs-group-by",{"title":5,"description":1065},"blog\u002Fsql-window-functions-vs-group-by","Window Functions vs GROUP BY","Window Functions","window-functions","2026-06-21","JnLD_5FUmKxwj5ND1XpR9Zkw4hHj3rHhl_iOmpX6iKQ",1782244088076]