diff --git a/src/40select.js b/src/40select.js index e55a49474d..870d233efc 100755 --- a/src/40select.js +++ b/src/40select.js @@ -139,11 +139,12 @@ yy.Select = class Select { Select statement in expression */ toJS(context) { + var outerContext = context === 'g' ? '(this.groupSources.get(g) || g)' : context; var s = 'alasql.utils.flatArray(this.queriesfn[' + (this.queriesidx - 1) + '](this.params,null,' + - context + + outerContext + '))[0]'; // var s = '(ee=alasql.utils.flatArray(this.queriesfn['+(this.queriesidx-1)+'](this.params,null,'+context+')),console.log(999,ee),ee[0])'; diff --git a/src/423groupby.js b/src/423groupby.js index 8830c83f3d..39461210fe 100755 --- a/src/423groupby.js +++ b/src/423groupby.js @@ -36,6 +36,7 @@ yy.Select.prototype.compileGroup = function (query) { var tableid = ''; } var defcols = query.defcols; + query.groupSources = new WeakMap(); var allgroup = [[]]; if (this.group) { allgroup = decartes(this.group, query); @@ -181,7 +182,7 @@ yy.Select.prototype.compileGroup = function (query) { }) .join(''); - s += '}' + aft + ',g));' + aft2 + '} else {'; + s += '}' + aft + ',g));this.groupSources.set(g,Object.assign({},p));' + aft2 + '} else {'; s += query.selectGroup .map(function (col) { var colas = col.nick; diff --git a/src/424select.js b/src/424select.js index 0d32d21ce0..b7d7e4b999 100755 --- a/src/424select.js +++ b/src/424select.js @@ -639,7 +639,11 @@ yy.Select.prototype.compileSelectGroup1 = function (query) { // // s += ';'; // console.log(col);//,col.toJS('g','')); - s += n2u(col.toJS('g', '')) + ';'; + if (col instanceof yy.Column) { + s += n2u(col.toJS('(this.groupSources.get(g) || g)', query.defaultTableid)) + ';'; + } else { + s += n2u(col.toJS('g', '')) + ';'; + } /*/* s += 'g[\''+col.nick+'\'];'; @@ -703,7 +707,8 @@ yy.Select.prototype.compileSelectGroup2 = function (query) { var key = (col.tableid || '') + '\t' + col.columnid; groupCol = groupColMap[key]; } - var isInGroup = groupCol !== null || query.ingroup.indexOf(col.nick) > -1; + var isInGroup = + (groupCol !== null && groupCol !== undefined) || query.ingroup.indexOf(col.nick) > -1; if (isInGroup) { // For columns in GROUP BY, use the GROUP BY column's nick if available var groupNick = (groupCol && groupCol.nick) || col.nick; diff --git a/test/test1106.js b/test/test1106.js new file mode 100644 index 0000000000..83926d3c00 --- /dev/null +++ b/test/test1106.js @@ -0,0 +1,33 @@ +if (typeof exports === 'object') { + var assert = require('assert'); + var alasql = require('..'); +} else { + __dirname = '.'; +} + +describe('Test 1106 - Correlated subquery with grouping', function () { + before(function () { + alasql('CREATE DATABASE test1106'); + alasql('USE test1106'); + alasql('CREATE TABLE scores (team STRING, name STRING, score INT)'); + alasql( + 'INSERT INTO scores VALUES ("A", "alice", 10), ("A", "alice", 5), ("A", "bob", 5), ("C", "charlie", 10)' + ); + }); + + after(function () { + alasql('DROP DATABASE test1106'); + }); + + it('resolves the outer row in a grouped scalar subquery', function () { + var result = alasql( + 'SELECT team, name, SUM(score) AS personal_score, (SELECT SUM(score) FROM scores AS i WHERE i.team = o.team) AS group_score FROM scores AS o GROUP BY name' + ); + + assert.deepStrictEqual(result, [ + {team: 'A', name: 'alice', personal_score: 15, group_score: 20}, + {team: 'A', name: 'bob', personal_score: 5, group_score: 20}, + {team: 'C', name: 'charlie', personal_score: 10, group_score: 10}, + ]); + }); +});