Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for alias omission in aggregate expressions #300

Merged
merged 2 commits into from Aug 26, 2014

Conversation

jpcody
Copy link

@jpcody jpcody commented Jul 27, 2014

This fix should be backwards-compatible, but I'm not confident it's being applied at the appropriate level.

When using aggregate expressions in a HAVING claus, an alias was forced, causing a syntax error in Postgres. The following Arel:

posts    = Arel::Table.new(:posts)
comments = Arel::Table.new(:comments)

posts.
  join(comments).on(posts[:id].eq(comments[:post_id])).
  having(comments[:rating].average.gt(90)).
  project(Arel.star).
  to_sql

Produces:

SELECT * FROM "posts" INNER JOIN "comments" ON "posts"."id" = "comments"."post_id" HAVING AVG("comments"."rating") AS avg_id > 90

Which leads to the following error: ActiveRecord::StatementInvalid: PG::SyntaxError: ERROR: syntax error at or near "AS" because Postgres (and maybe others?) disallows aliases in HAVING clauses.

This fix allows these aggregate functions to take an optional argument that can either override the avg_id default string or be nil to skip the alias altogether, while maintaining the default behavior.

Now we could do:

posts    = Arel::Table.new(:posts)
comments = Arel::Table.new(:comments)

posts.
  join(comments).on(posts[:id].eq(comments[:post_id])).
  having(comments[:rating].average(nil).gt(90)).
  project(Arel.star).
  to_sql

To yield:

SELECT * FROM "posts" INNER JOIN "comments" ON "posts"."id" = "comments"."post_id" HAVING AVG("comments"."rating") > 90

And avoid syntax errors.

@rafaelfranca
Copy link
Member

While I agree with this patch I find that passing nil as argument does say what that argument does. For me it seems it is trying to calculate the average of nil. Maybe we should take a hash with a alias option.

cc @tenderlove

@matthewd
Copy link
Member

IMO this is rather back-to-front... the alias shouldn't be part of the aggregate to begin with: it's properly part of the 'project' production, not the function call. And contrariwise, our motivation for applying the alias there (predictability of the output column name, I guess?) should presumably apply equally to any non-aggregate complex expression.

@jpcody
Copy link
Author

jpcody commented Jul 28, 2014

@matthewd Agreed, the alias inclusion felt odd to begin with, particularly because Arel makes affordances for explicit aliases. But it seemed to have been there since nearly the beginning of time, so I was gun-shy on touching it.

I could remove the alias and ensure the tests still pass, and maybe @tenderlove as the original author of that would be able to hit the brakes if that seems to violate the original motivation?

@jpcody
Copy link
Author

jpcody commented Jul 31, 2014

OK, I had some more time this morning, and I've removed the default aggregate aliases altogether. There were some FIXMEs asking if this was still needed, and it's my opinion they're not. Because aliasing with as on aggregates is totally possible, it doesn't make sense to default to behavior that breaks having clauses.

The only other thing I can think of is that there are occasions I'm unaware of where generating an alias is necessary on aggregate functions, but Googling around turns nothing up there.

(It's worth noting that this change could very-well break existing code that relies on the aliases that are generated.)

@jpcody
Copy link
Author

jpcody commented Aug 26, 2014

@rafaelfranca I know you're quite busy with 4.2 betas (thanks and kudos!), but I'm curious if there's any more I can do to help this one across the finish line?

@rafaelfranca
Copy link
Member

I'll defer to @matthewd

@matthewd
Copy link
Member

I think it's fair to treat the name as undefined here, given that DBs have differing opinions on the default; if you need a particular value, you should specify an explicit alias. (Or just access the column by position, as we do in Rails.)

matthewd added a commit that referenced this pull request Aug 26, 2014
Allow for alias omission in aggregate expressions
@matthewd matthewd merged commit 36836fa into rails:master Aug 26, 2014
sgrif added a commit that referenced this pull request Oct 30, 2014
This reverts commit 36836fa, reversing
changes made to 53bc842.
sgrif added a commit that referenced this pull request Oct 31, 2014
This reverts commit 9b92af7.

beta2 is out, and we've fixed the issue that this caused in Rails
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants