-
Notifications
You must be signed in to change notification settings - Fork 11.4k
[5.0] Fix aggregate function to deal with group by sql #8113
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
Conversation
It works with count. But what about other aggregate functions (min, max, sum, avg) ? |
@codelight89 That's a good point and something that needs to be addressed, I'd say. An issue is that in general we shouldn't collapse the database result per group into a single value, as that is valid in the paginator context but not necessarily in other cases. Thus a more general solution would return |
@JoostK, I agree, this would be a more general solution. |
I'm open to pulls to this branch on my fork. |
May I do this? |
@codelight89 Of course. :) |
If you are up to the task, fine with me 👍 My |
@GrahamCampbell, I sent a pull request. @JoostK, agregate function must return array only when we have more than one result, correct? On one row it returns scalar value |
@@ -1562,7 +1564,7 @@ public function exists() | |||
* Retrieve the "count" result of the query. | |||
* | |||
* @param string $columns | |||
* @return int | |||
* @return mixed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JoostK Should this be array|int
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changing it. Tell me if I'm wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other aggregate functions - mixed
Should be changed too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should. I noticed when creating the PR, as I never look at docblocks I didn't thnk about updating it earlier. The same is true for any of the other aggregate methods (and aggregate itself).
Now that I think about it, perhaps it's better to collapse grouped results to a single value in all cases, because the behaviour now depends on having set groupBy
or not which is kind of unpleasant. Moreover, the actual group is not accessible so all you currently have is an array of numbers for which you do not know to which group they belong, so perhaps just aggregate them manually in PHP. I will send another PR to accomplish this so you can better see what I mean.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, maybe you're right.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codelight89 We should avoid mixed if we can, because it's pretty useless documentation.
Do y'all think we could add a few integration tests that actually hit the database to give this a whirl? There is an integration test class already setup we should be able to use. |
@JoostK, are you sure that avg will return expected result in current realization? now it calculates avg of avg's not avg of the column. |
@codelight89 What do you propose for it? Perhaps we should just keep it simple and only support |
@JoostK, maybe we should execute aggregate functions (except count) without grouping (backup group field before executing and restore it after). Somethig like this This function may be modified to:
|
What is the purpose of this at all? If one wants single value result, then there is literally no reason for Am I missing anything here? |
@jarektkaczyk, first at all this is for grouped paginated request that doesn't work correct because count aggregate function doesn't work with grouped request. But I think it will be good if other aggregate functions will work correct in all cases. Am I right? |
@codelight89 Fair enough with pagination. However, if we talk about other cases, I'm not sure if
should it count all the rows (why group by then)? should it count in groups and return multiple results (why not lists/get then)?
the same here: max of all rows (why group by then)? groupped max (why not lists/get then)? and so on. Show me a use-case please, if I'm wrong. |
@jarektkaczyk, I understand you, it's a bad case to use it. Anyway do you think that the first row is the best option? Do you think better to leave it as it is? |
@jarektkaczyk If you go through the separate commits you will see how I changed it to become like this, although I do agree with you that some of this doesn't really make sense. To answer your questions:
What we're trying to solve here is the problem with pagination for grouped queries. The current solution solves this issue by counting the number of returned groups, which equals the total number of results for the query. So, count in groups is what happens in
I agree with you here, the current approach makes little sense. The reasoning for it is that I didn't like returning various kinds of results (array/scalar) depending on if a group by statement was present. The problem with returning an array is that the array's values do in fact give you the results per group, but do not contain any information about the group the value belongs to, therefore being rather useless. In retrospect, only changing |
@JoostK Yeah, I understand the pagination issue, nothing against this one. I just don't really see a reason for changing the behaviour in any case, other than pagination (even groupped count, but not for pagination). |
@jarektkaczyk How would you go about changing it only for pagination? |
@JoostK I suppose this would be enough (a quick tinkering, no time for a PR now with tests, but you'll get the idea anyway):
|
Small fix. |
@codelight89 yep, good catch ... or in fact, not really :) It was there on purpose: for consistency and flexibility. Being it |
I would prefer if the Overall, I think I like your specific pagination counting better than this PR, as it leaves the aggregate method in itself unchanged. Perhaps we could refactor a bit to avoid the code duplication. |
@JoostK It doesn't matter whether it's groupped or not if this isn't true |
Signed-off-by: Graham Campbell <graham@mineuk.com>
Signed-off-by: Graham Campbell <graham@mineuk.com>
@GrahamCampbell later you can squash all commits if you want. But now I think better to leave them for better understanding of discussion here. |
I've already squashed them as far as possible. We need to retain all authorship. |
@codelight89 You need to restore the tests you deleted in the last commit please. |
{ | ||
if (isset($this->groups)) return count($results); | ||
|
||
return (int) array_change_key_case((array) $results[0])['aggregate']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this valid syntax for php 5.4?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, it's valid
Function array dereferencing has been added, e.g. foo()[0].
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, good. I couldn't remember if it was added in 5.4, or 5.5. :) I only use 5.5/5.6 on prod.
This tests were written for already deleted code |
We still need tests for this, even if they're not the same tests. |
Without tests, there's no evidence your changes actually work. |
@GrahamCampbell I think you must rename this PR. Because now it's about fixing pagination for grouped request |
I'll recreate it... |
Ok then, so the docblock changes are now here: #8309. |
And the rest is here: #8310. |
Replaces #7372 and #8112.
// cc @fcjailybo, @JoostK, @codelight89