Skip to content

Commit 5a2538d

Browse files
Copilotmathiasrw
andauthored
ORDER BY clause for multiple UNIONs to fix #7 (#2188)
Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: mathiasrw <[email protected]> Co-authored-by: Mathias Wulff <[email protected]>
1 parent 3cdd721 commit 5a2538d

File tree

6 files changed

+936
-759
lines changed

6 files changed

+936
-759
lines changed

src/38query.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,34 @@ function queryfn3(query) {
249249
query.data = arrayIntersectDeep(query.data, ud);
250250
}
251251

252+
// Populate order keys for UNION/INTERSECT/EXCEPT before ordering
253+
if (
254+
query.orderfn &&
255+
query.orderColumns &&
256+
(query.unionallfn || query.unionfn || query.exceptfn || query.intersectfn)
257+
) {
258+
for (i = 0, ilen = query.data.length; i < ilen; i++) {
259+
for (var idx = 0; idx < query.orderColumns.length; idx++) {
260+
var v = query.orderColumns[idx];
261+
var key = '$$$' + idx;
262+
var r = query.data[i];
263+
if (v instanceof yy.Column && r[v.columnid] !== undefined) {
264+
r[key] = r[v.columnid];
265+
} else if (v instanceof yy.Column) {
266+
// Column not found in row, set to null or undefined
267+
r[key] = undefined;
268+
} else {
269+
// For expressions, we'd need to evaluate them, but for now just skip
270+
r[key] = undefined;
271+
}
272+
// Add to removeKeys if not already there
273+
if (i === 0 && query.removeKeys.indexOf(key) === -1) {
274+
query.removeKeys.push(key);
275+
}
276+
}
277+
}
278+
}
279+
252280
// Ordering
253281
if (query.orderfn) {
254282
if (query.explain) var ms = Date.now();

src/40select.js

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,8 @@ yy.Select = class Select {
223223
// 8. Compile ORDER BY clause
224224
if (this.order) {
225225
query.orderfn = this.compileOrder(query, params);
226+
// Copy orderColumns to query for union handling
227+
query.orderColumns = this.orderColumns;
226228
}
227229

228230
if (this.group || query.selectGroup.length > 0) {
@@ -254,16 +256,28 @@ yy.Select = class Select {
254256
query.corresponding = this.corresponding; // If CORRESPONDING flag exists
255257
if (this.union) {
256258
query.unionfn = this.union.compile(databaseid);
257-
query.orderfn = this.union.order ? this.union.compileOrder(query, params) : null;
259+
// ORDER BY is now at the top level, not in the union clause
260+
if (!query.orderfn && this.union.order) {
261+
query.orderfn = this.union.compileOrder(query, params);
262+
}
258263
} else if (this.unionall) {
259264
query.unionallfn = this.unionall.compile(databaseid);
260-
query.orderfn = this.unionall.order ? this.unionall.compileOrder(query, params) : null;
265+
// ORDER BY is now at the top level, not in the unionall clause
266+
if (!query.orderfn && this.unionall.order) {
267+
query.orderfn = this.unionall.compileOrder(query, params);
268+
}
261269
} else if (this.except) {
262270
query.exceptfn = this.except.compile(databaseid);
263-
query.orderfn = this.except.order ? this.except.compileOrder(query, params) : null;
271+
// ORDER BY is now at the top level, not in the except clause
272+
if (!query.orderfn && this.except.order) {
273+
query.orderfn = this.except.compileOrder(query, params);
274+
}
264275
} else if (this.intersect) {
265276
query.intersectfn = this.intersect.compile(databaseid);
266-
query.orderfn = this.intersect.order ? this.intersect.compileOrder(query, params) : null;
277+
// ORDER BY is now at the top level, not in the intersect clause
278+
if (!query.orderfn && this.intersect.order) {
279+
query.orderfn = this.intersect.compileOrder(query, params);
280+
}
267281
}
268282

269283
// SELECT INTO

src/424select.js

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,15 @@ yy.Select.prototype.compileSelect1 = function (query, params) {
354354
};
355355
yy.Select.prototype.compileSelect2 = function (query, params) {
356356
var s = query.selectfns;
357-
if (this.orderColumns && this.orderColumns.length > 0) {
357+
// Only add order keys if there's no union operation (otherwise they'll be added later)
358+
if (
359+
this.orderColumns &&
360+
this.orderColumns.length > 0 &&
361+
!this.union &&
362+
!this.unionall &&
363+
!this.except &&
364+
!this.intersect
365+
) {
358366
this.orderColumns.forEach(function (v, idx) {
359367
var key = '$$$' + idx;
360368
// Handle positional column reference (for SELECT * with ORDER BY numeric)
@@ -527,7 +535,15 @@ yy.Select.prototype.compileSelectGroup2 = function (query) {
527535
}
528536
});
529537

530-
if (this.orderColumns && this.orderColumns.length > 0) {
538+
// Only add order keys if there's no union operation (otherwise they'll be added later)
539+
if (
540+
this.orderColumns &&
541+
this.orderColumns.length > 0 &&
542+
!this.union &&
543+
!this.unionall &&
544+
!this.except &&
545+
!this.intersect
546+
) {
531547
this.orderColumns.forEach(function (v, idx) {
532548
// console.log(411,v);
533549
var key = '$$$' + idx;

src/alasqlparser.jison

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -506,7 +506,7 @@ WithTable
506506
/* SELECT */
507507

508508
Select
509-
: SelectClause RemoveClause? IntoClause FromClause PivotClause? WhereClause GroupClause OrderClause LimitClause UnionClause
509+
: SelectClause RemoveClause? IntoClause FromClause PivotClause? WhereClause GroupClause UnionClause OrderClause LimitClause
510510
{
511511
yy.extend($$,$1); yy.extend($$,$2); yy.extend($$,$3); yy.extend($$,$4);
512512
yy.extend($$,$5); yy.extend($$,$6);yy.extend($$,$7);
@@ -524,6 +524,16 @@ Select
524524
}
525525
;
526526

527+
SelectWithoutOrderOrLimit
528+
: SelectClause RemoveClause? IntoClause FromClause PivotClause? WhereClause GroupClause UnionClause
529+
{
530+
yy.extend($$,$1); yy.extend($$,$2); yy.extend($$,$3); yy.extend($$,$4);
531+
yy.extend($$,$5); yy.extend($$,$6);yy.extend($$,$7);yy.extend($$,$8);
532+
$$ = $1;
533+
if(yy.exists) $$.exists = yy.exists.slice();
534+
}
535+
;
536+
527537
PivotClause
528538
: PIVOT LPAR Expression FOR Literal PivotClause2? RPAR AsLiteral?
529539
{ $$ = {pivot:{expr:$3, columnid:$5, inlist:$6, as:$8}}; }
@@ -1074,21 +1084,21 @@ HavingClause
10741084

10751085
UnionClause
10761086
: { $$ = undefined; }
1077-
| UNION Select
1087+
| UNION SelectWithoutOrderOrLimit
10781088
{ $$ = {union: $2} ; }
1079-
| UNION ALL Select
1089+
| UNION ALL SelectWithoutOrderOrLimit
10801090
{ $$ = {unionall: $3} ; }
1081-
| EXCEPT Select
1091+
| EXCEPT SelectWithoutOrderOrLimit
10821092
{ $$ = {except: $2} ; }
1083-
| INTERSECT Select
1093+
| INTERSECT SelectWithoutOrderOrLimit
10841094
{ $$ = {intersect: $2} ; }
1085-
| UNION CORRESPONDING Select
1095+
| UNION CORRESPONDING SelectWithoutOrderOrLimit
10861096
{ $$ = {union: $3, corresponding:true} ; }
1087-
| UNION ALL CORRESPONDING Select
1097+
| UNION ALL CORRESPONDING SelectWithoutOrderOrLimit
10881098
{ $$ = {unionall: $4, corresponding:true} ; }
1089-
| EXCEPT CORRESPONDING Select
1099+
| EXCEPT CORRESPONDING SelectWithoutOrderOrLimit
10901100
{ $$ = {except: $3, corresponding:true} ; }
1091-
| INTERSECT CORRESPONDING Select
1101+
| INTERSECT CORRESPONDING SelectWithoutOrderOrLimit
10921102
{ $$ = {intersect: $3, corresponding:true} ; }
10931103
;
10941104

0 commit comments

Comments
 (0)