diff --git a/src/424select.js b/src/424select.js index b7d7e4b999..dca58a7036 100755 --- a/src/424select.js +++ b/src/424select.js @@ -684,14 +684,52 @@ yy.Select.prototype.compileSelectGroup1 = function (query) { yy.Select.prototype.compileSelectGroup2 = function (query) { var self = this; var s = query.selectgfns; + var hasOrderColumns = + this.orderColumns && + this.orderColumns.length > 0 && + !this.union && + !this.unionall && + !this.except && + !this.intersect; + var needsOrderColumnMaps = + hasOrderColumns && + this.orderColumns.some(function (col) { + return col instanceof yy.Column; + }); // Create a lookup map for GROUP BY columns to optimize performance var groupColMap = {}; + var groupProjectedColumnMap = {}; + var projectedSelectColumnMap = {}; if (self.group) { self.group.forEach(function (gp) { var key = (gp.tableid || '') + '\t' + gp.columnid; groupColMap[key] = gp; }); + if (needsOrderColumnMaps) { + self.columns.forEach(function (col) { + if (col instanceof yy.Column) { + var key = (col.tableid || '') + '\t' + col.columnid; + if (groupColMap[key]) { + if (!col.as) { + groupProjectedColumnMap[key] = col.columnid; + } else if (!groupProjectedColumnMap[key]) { + groupProjectedColumnMap[key] = col.as; + } + } + } + }); + } + } + if (needsOrderColumnMaps) { + self.columns.forEach(function (col) { + if (!(col instanceof yy.Column && col.columnid === '*')) { + var projectedSelectKey = col.as || (col instanceof yy.Column ? col.columnid : col.nick); + if (projectedSelectKey) { + projectedSelectColumnMap[projectedSelectKey] = true; + } + } + }); } self.columns.forEach(function (col) { @@ -717,24 +755,22 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { }); // Only add order keys if there's no union operation (otherwise they'll be added later) - if ( - this.orderColumns && - this.orderColumns.length > 0 && - !this.union && - !this.unionall && - !this.except && - !this.intersect - ) { + if (hasOrderColumns) { this.orderColumns.forEach(function (v, idx) { // console.log(411,v); var key = '$$$' + idx; + var groupKey = (v.tableid || '') + '\t' + v.columnid; // console.log(427,v,query.groupColumns,query.xgroupColumns); // Handle positional column reference (for SELECT * with ORDER BY numeric) if (v._useColumnIndex !== undefined) { // Use Object.keys to get column names and access by index s += "var keys=Object.keys(r);r['" + key + "']=r[keys[" + v.columnIndex + ']];'; - } else if (v instanceof yy.Column && query.groupColumns[v.columnid]) { + } else if (v instanceof yy.Column && groupProjectedColumnMap[groupKey]) { + s += "r['" + key + "']=r['" + groupProjectedColumnMap[groupKey] + "'];"; + } else if (v instanceof yy.Column && projectedSelectColumnMap[v.columnid]) { s += "r['" + key + "']=r['" + v.columnid + "'];"; + } else if (v instanceof yy.Column && groupColMap[groupKey]) { + s += "r['" + key + "']=g['" + groupColMap[groupKey].nick + "'];"; } else { s += "r['" + key + "']=" + v.toJS('g', '') + ';'; } diff --git a/test/test2515.js b/test/test2515.js new file mode 100644 index 0000000000..ff605263d2 --- /dev/null +++ b/test/test2515.js @@ -0,0 +1,75 @@ +if (typeof exports === 'object') { + var assert = require('assert'); + var alasql = require('..'); +} + +describe('Test 2515 - ORDER BY original grouped column with selected alias', function () { + it('A) Orders ascending by original grouped column name', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'two'}, + ]; + + var res = alasql( + 'SELECT num AS position, letter AS note FROM ? GROUP BY num, letter ORDER BY num', + [data] + ); + + assert.deepStrictEqual(res, [ + {position: 10, note: 'two'}, + {position: 50, note: 'two'}, + {position: 100, note: 'one'}, + ]); + }); + + it('B) Orders ascending by original grouped column name with explicit ASC', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'two'}, + ]; + + var res = alasql( + 'SELECT num AS position, letter AS note FROM ? GROUP BY num, letter ORDER BY num ASC', + [data] + ); + + assert.deepStrictEqual(res, [ + {position: 10, note: 'two'}, + {position: 50, note: 'two'}, + {position: 100, note: 'one'}, + ]); + }); + + it('C) Orders descending by original grouped column name', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'two'}, + ]; + + var res = alasql( + 'SELECT num AS position, letter AS note FROM ? GROUP BY num, letter ORDER BY num DESC', + [data] + ); + + assert.deepStrictEqual(res, [ + {position: 100, note: 'one'}, + {position: 50, note: 'two'}, + {position: 10, note: 'two'}, + ]); + }); + + it('D) Orders by grouped source column that is not projected', function () { + var data = [ + {num: 100, letter: 'one'}, + {num: 50, letter: 'two'}, + {num: 10, letter: 'three'}, + ]; + + var res = alasql('SELECT letter AS note FROM ? GROUP BY num, letter ORDER BY num', [data]); + + assert.deepStrictEqual(res, [{note: 'three'}, {note: 'two'}, {note: 'one'}]); + }); +});