It would be very useful for to have a GROUP_CONCAT available as an aggregate function. The best use case is with Drupal Commerce, where a view of product display nodes could aggregate the related product entities as 'pid1,pid2,pid3,etc'. The add to cart form field handler could then explode those again to produce a multi-product form.
As a sideline to #1359298: Support Plugins for Views Aggregate in D7 (D8 Backport) I've coded a proof-of-concept version.
If this looks okay, how about moving views_query_default_aggregation_method_simple() and the other two functions that sit at the bottom of views_plugin_query_default.inc into this query extender as well?
Comment | File | Size | Author |
---|---|---|---|
#89 | reroll_diff_1362524_86-89.txt | 10.57 KB | ankithashetty |
#89 | 1362524-89.patch | 17.29 KB | ankithashetty |
| |||
#86 | views-1362524-86.patch | 16.85 KB | thetwentyseven |
| |||
#85 | views-1362524-85.patch | 16.99 KB | thetwentyseven |
#36 | add-group_concat-aggregate-function-1362524-36-3.8-do-not-test.patch | 9.23 KB | killua99 |
Comments
Comment #1
joachim CreditAttribution: joachim commentedHere's the patch.
Works fine, but it's proof of concept with regard to the implementation and there would be cleanup to do (see above) and also the postgres version of the query extender class.
Try it with a view of nodes grouped on uid and GROUP_CONCAT on nid or title.
Comment #2
joachim CreditAttribution: joachim commentedHere's the patch with the changes described above:
- the standalone functions are all moved to the new query extender
- the info in get_aggregation_info() is updated to give the extender class as well (in anticipation of #1359298: Support Plugins for Views Aggregate in D7 (D8 Backport))
Should the extender class be moved to an inc file?
Comment #3
pbo CreditAttribution: pbo commentedJoachim,
Thanks for the patch; i'm trying to create a view with a one-to-many relation, the best solution to this (afaik) is to group-concat the multi values and explode them again when using them. I was actually surprised that only the basic min/max/avg/count aggregate functions were available; a group-concat seems a logical addition?
Will this patch be taken in the next release? (i'm new to drupal so i don't know how this gets done....)
Paul
Comment #4
joachim CreditAttribution: joachim commented> Will this patch be taken in the next release? (i'm new to drupal so i don't know how this gets done....)
People like yourself need to review it and then the maintainer of this project needs to accept the patch and commit it.
Comment #5
chx CreditAttribution: chx commentedhttp://stackoverflow.com/questions/970481/concat-all-column-values-in-sql this is very relevant. The
array_to_string(ARRAY(SELECT unnest(array_agg(column)) ORDER BY 1), separator)
should work on DB2, too.Comment #6
pbo CreditAttribution: pbo commentedYes, i see the issue but as long as the idea remains the same, then a db abstraction could fill in the syntactical differences, right? And maybe also even to provide an explode-alike-function to unpack the values.
Paul
Comment #7
dawehnerQuery extenders can be written special for a certain db driver, just suffix with _mysql for example, sure that's not that important for this particular issue but a quite cool feature.
Comment #8
joachim CreditAttribution: joachim commentedYup, that's right, so to add support for Postgres to this patch, we need something like this:
I don't have postgres installed though...
Comment #9
dema502 CreditAttribution: dema502 commentedfor postgresql you can use string_agg
http://www.postgresql.org/docs/9.0/static/functions-aggregate.html
or array_agg and array_to_string
http://www.postgresql.org/docs/8.4/static/functions-aggregate.html
Comment #10
joachim CreditAttribution: joachim commentedHere's a reroll to keep up with changes on the main branch.
I've also added a fair bit to the code documentation and renamed some variables to be clearer, as revisiting this code which *I wrote* just a couple of months ago had me baffled at first -- not a good sign!
I'm a bit unsure about how to get the Postgres class to work. The answer on StackOverflow gives this as the expression to use:
I presume 'foo' is the name of the table? In which case, doesn't that mean that in fact we need to reproduce the entire query within that SELECT to get right rows to aggregate together?
If anyone has Postgres and wants to do some experimentation, here's the class to add to the end of the patched file. It needs some work, obviously :)
Comment #11
tim.plunkettTriggering the testbot.
Comment #12
akoepke CreditAttribution: akoepke commentedGreat work so far on the group_concat, has been very useful in a project I am currently working on.
Is it possible to add a settings form so we can specify a different separator. At the moment I have changed the code in the patch so that it uses a newline character which works for my case. I have had a look through the code and seen that there isn't any variable in the addAggregateGroupConcat function that could store this sort of setting.
Comment #13
joachim CreditAttribution: joachim commentedThese aren't yet at a stage where they can open up user options. That's maybe something we can look at as a follow-on to this patch.
Comment #14
semanthis CreditAttribution: semanthis commentedApplying this patch manually I end up with : SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax. Do I apply it against the wrong version (7.x-3.x-dev). What would I need to do to apply the patch in a regular way? I seem to be to stupid to deal with git. It would be great if anyone could help me.
Comment #15
semanthis CreditAttribution: semanthis commented#10: 1362524-3.views_.group-concat-aggregate.patch queued for re-testing.
Comment #16
tordeu CreditAttribution: tordeu commentedFirst let me thank you for working on this patch. I think it is a very important feature to have. I am uncertain if this is the right place to post this problem/limitation, but I hope it's not too bad.
I am currently using the patch to display related nodes in a view (short explanation: I have "book" nodes and "author" nodes, connected through a relation (is written by) and I created a view of all books and for every book I list the title and all the authors).
I have noticed a problem with the patch when it comes to creating links to the original nodes.
Let's say book 1 that has two relations to author A and author B. It the views listing all the books, it lists "A, B" as the authors of book 1 as expected (well, actually it does not use a space after the comma, but whatever")
But: The problem is that the linking to the original content does not work when using GROUP_CONCAT. Instead of linking "A" to let's say node/10 and "B" to node/11, a link "A,B" is created which links to node/10,11. So, it's not possible to visit the page of the second author.
I am not too intimate with SQL, but I am not too surprised this happens, because it probably not only concatenates the values of the cells, but also the ids of the nodes and then drupal uses the concatenated node ids to create the link (at least that is how I imagine it), but I wonder if there is a way to make this patch support linking to the original content. This would make it possible to use the patch instead of using Views Field View, which seems pretty horrible form a performance perspective.
Comment #17
joachim CreditAttribution: joachim commented> But: The problem is that the linking to the original content does not work when using GROUP_CONCAT. Instead of linking "A" to let's say node/10 and "B" to node/11, a link "A,B" is created which links to node/10,11. So, it's not possible to visit the page of the second author.
You'd need to write a custom handler for that, which would need to be smart enough to know how to take its value of '10,11', explode() it on the comma, and then format two links.
That's out of the scope of this patch.
Comment #18
remaye CreditAttribution: remaye commentedIs this available somewhere for views3 D6 ?
Comment #19
dasjoi have just used the patch in #10 successfully while working on my geocluster project. thanks!
didn't give it a throughout review, but it works and code looks clean.
Comment #20
warmth CreditAttribution: warmth commentedIs this already committed on Drupal 7 version?
#10 applied and worked here with some small limitations:
it can only be used once or the result is something crazyComment #21
developerweeks CreditAttribution: developerweeks commentedIsn't the link trouble listed here because the link processing is done after the values are fetched? Therefore, the lovely work done here (views integration is tricky stuff, and I have been looking for exactly this) does not have a method yet overriden for the formatting of the values. This patch makes the returned value (single value) be a string containing several commas and infromation. When the value is handed off to drupal, it is as a single string and Drupal uses the same formatting processors on this string that it does for others. Next version will need to override the link formatter when this is engaged.
Comment #22
joachim CreditAttribution: joachim commented#21: Yes, that's exactly it. This works at the query level, and the formatter gets something like 'a, b, c'. If it tries to make a link out of that, trouble ensues.
Comment #23
DYdave CreditAttribution: DYdave commentedThanks a lot guys for all your comments and feedbacks.
It seems this issue is getting more activity now, after being paused for about two months, until #20 got back with a quick feedback summary.
Unfortunately, it seems this is still going to need more work, testing, feedback, discussion, and I would think it would still need a bit more time before being committed.
joachim's comment (#22):
reminded me of an idea I had initially to be able to add links or some kind of specific formatters.
Pretty much, I was thinking of some kind of mechanism to explode the concatenated list of values (for example, 'a, b, c'), with a specific separator, then format each value and concatenate them again for display.
But I quickly found out it could become much more complicated than what I thought, for example, for building the links, from values 'a, b, c'. If these were nids (or other objects IDs), then I guess it would already make things slightly easier to build the corresponding links, but otherwise, it could certainly become much more complicated. Not to mention variations on the separators for the values (before and after formatting) and such.....
I haven't done any tests of implementation of that yet, so I'm not even sure this would lead anywhere, but I just wanted to share this idea quickly to get some more feedback and discussions on this while there is some activity.
I also think items raised by #20 related with special characters and distinct should be addressed. In particular for the special characters, I didn't have time to take a closer look at this, but I would be very interested in hearing what others would have to say about it.
Any more feedback, comments, questions or testing would be greatly appreciated.
Thanks to all in advance.
Comment #24
dbehrman CreditAttribution: dbehrman commentedI had a problem installing the patch, but I also wanted a way to add more aggregation functions, so I patched the original views_plugin_query_default::get_aggregation_info() to have a hook. So now you can add aggregation methods in any module by calling hook_aggregation_info. The second file attached is example code for adding a few new aggregate functions.
Comment #25
warmth CreditAttribution: warmth commentedThat's awesome dude, that will bring a lot of new custom options. Thanks, I can wait to see that committed and used.
Comment #26
derhasi CreditAttribution: derhasi commentedI guess that is not a consistent approach, as the rest of views extends via plugins and handlers. In the given case you could simply extend views_plugin_query_default and override its get_aggregation_info() method.
The query handler should know what it is aware of, and should not be told that by other modules, as this is in the end only a matter of what the DB layer supports.
Comment #27
windmaomao CreditAttribution: windmaomao commentedvery solid and inspiring. BTW, this is something which i think the view is really lacking. Dashboard and any data analysis used a quite often of this feature.
Comment #28
robertwb CreditAttribution: robertwb commentedWondering if the patch that you posed is still the *best* way to go about this issue, as opposed to the way taken in #24. It seemed to me that #26 was suggesting that the #24 route was not a good route.
I am trying to build on this by adding some spatial aggregates for postGIS enabled Drupal installs.
Thanks,
r.b.
Comment #29
robertwb CreditAttribution: robertwb commentedTesting notes on the text aggregate in PostgreSQL. There appears to be configuration issues with the settings specified in both of the patches supplied above, at least in my install of Drupal using postgreSQL. Also, because of the lack of the group_concat function in PG you have to roll your own to test the base case for this thread. I will present some code to set up the aggregates that are needed, and also I will share my modifications to the settings that I *think* are in error above (though it may just be my homegrown group_concat functions that are causing this mess).
I am not offering this as a patch because I am unsure if I should be patching the base code or the patch(es) given above. I appreciate any feedback.
Possible Errors in Config:
* Group_concat aggregates fail (creating an erroneous query) in Views on postgreSQL unless they are run as a "DISTINCT", which can be added with the following config option:
* Using the group_concat aggregate on a text column in Drupal 7.x with the configs given creates a functioning piece of SQL that properly accesses the group_concat function, but when rendered by Drupal views it returns the string "0" instead of the concatenated string that the query correctly produces. This is fixed with the entry in the code given above where the views handler is specified:
Code needed to use group_concat on postgreSQL.
Comment #30
mpgeek CreditAttribution: mpgeek commentedThere shouldn't be any space between the function name and the openning parenthesis. This patch fixes that for GROUP_CONCAT.
Comment #31
pschuelke CreditAttribution: pschuelke commentedI applied the patch on the 3.x-dev batch the patch failed
Here's a re-roll of #30 for the March, 28 2014 update.
Comment #33
pschuelke CreditAttribution: pschuelke commented30: 1362524-30.views_.group-concat-aggregate.patch queued for re-testing.
Comment #34
pschuelke CreditAttribution: pschuelke commentedtry that again
Comment #35
danharper CreditAttribution: danharper commentedTried patch on 34 but says it's corrupt on line 25.
Cheers Dan
Comment #36
killua99 CreditAttribution: killua99 commentedReroll patch.
One is for use with the current 3.8 stable release and the other is for the current 7.x-3.x branch.
Comment #38
RoSk030: 1362524-30.views_.group-concat-aggregate.patch queued for re-testing.
Comment #39
balazswmann CreditAttribution: balazswmann commentedI think a "Concatenation separator" option (or something like this) also would be useful, so the user could specify an optional separator value. Hardcoded concatenation methods may not be appropriate.
Comment #40
WillowDigit CreditAttribution: WillowDigit commentedI've just joined to this queue. Patch #36 is flawed. It removes $info from function compile_fields(), and does not add 'method' => 'addAggregateGroupConcat' to array key 'group_concat', but adds 'method' => 'addAggregateSimple'. I eventually got it working. Nice :)
Comment #41
dillix CreditAttribution: dillix commented+1 for adding group_concat to views. It's very useful in shops.
Comment #42
TechNikh CreditAttribution: TechNikh commentedThanks @WillowDigit . Those steps worked for me too.
I created a patch for those fixes and attached it here along with interdiff between the patch in #36 and the new patch.
Comment #43
RoSk0Comment #44
euk CreditAttribution: euk commentedPatch from #42 worked for me fine.
Comment #45
tim.abbott CreditAttribution: tim.abbott commentedPatch from #42 worked great for me too.
Comment #46
jgullstr CreditAttribution: jgullstr commented#42 works for me too, thanks!
Comment #47
osopolarPatch from #42 works great for me too.
+1 for add a settings form to specify different separators in follow up issue.
Comment #48
nithinkolekar CreditAttribution: nithinkolekar commentedPatch worked fine with views merged rows + view rules for my specific requirement
Comment #49
damiankloip CreditAttribution: damiankloip commentedPatch is looking good but I think we might want some tests to go with this.
Comment #50
mpgeek CreditAttribution: mpgeek at Phase2 commentedThis is necessary for #2578785: Large-scale location mapping in Drupal 8 (Views). Adding as a related issue. ALso wonder if this should generally be dealt with in a separate issue for D8 coverge.
Comment #51
mvlabat CreditAttribution: mvlabat as a volunteer commentedFor user's sake I've changed the GROUP_CONCAT separator to ', '. I've found no way to add arguments (for aggregation functions) to the admin page, so this will be like a temporary placeholder.
Comment #52
mvlabat CreditAttribution: mvlabat as a volunteer commentedManual fixing patch files is not good...
Comment #53
robertwb CreditAttribution: robertwb commentedI think that this fits nicely in with the views plugin architecture. I have not looked through the D8 plumbing, but for D7, any number of aggregates may be exposed by modules by adding " + views_fetch_plugin_data('query_aggregate');" to the aggregate definition array. I have NOT updated the patch in this thread since it may wish to accomplish other things (like supporting the new extender class ViewsAggregateQuery). However, since the fix is so simple, I am copying the code below and creating a separate thread to make aggregate definitions pluggable.
Comment #54
osopolar@robertwb: I guess you refer to issue: #2662548: Support Plugins for Views Aggregate.
Will that be back-ported to D7?Edit: OK, it got already back-ported: #1359298: Support Plugins for Views Aggregate in D7 (D8 Backport). What does this mean for this issue? Should GROUP_CONCAT now be implemented as a separate views plugin or is the patch in #42 or #52 still valid?
Comment #55
robertwb CreditAttribution: robertwb commented@osopolar - I think the patch will need to be reconfigured if using the latest dev from views. The approach used in this patch will still be valid, but I think it better to extend with the new framework for portability.
Comment #56
MustangGB CreditAttribution: MustangGB commentedStill needs group_concat_distinct, here is my speedy chuck-it-in implementation:
Comment #57
MustangGB CreditAttribution: MustangGB commentedComment #58
lionguard CreditAttribution: lionguard as a volunteer commentedThe attached patch adds in a group concact (Distinct) function, and also removes null entries from concats to prevent RESULT,,RESULT,,, from appearing (instead, it would appear as RESULT, RESULT)
Comment #59
MustangGB CreditAttribution: MustangGB commentedAdded the requested test.
Comment #60
lionguard CreditAttribution: lionguard as a volunteer commentedShould the group_concat function also call on the CONVERT function, in order for it to work on non-Text datatypes? (see https://coderhub.wordpress.com/2012/10/17/apply-group_concat-and-concat-... for more background)
Comment #61
bryanmanalo CreditAttribution: bryanmanalo as a volunteer commentedWill this be added on a release?
Comment #62
robertwb CreditAttribution: robertwb commented@lionguard - seems like a reasonable contingency, though to make it cross-db-platform it may require alternative function calls.
@bryanmanalo - not sure if group_concat has been added but it is now trivial to do so in a custom module.
Comment #63
MustangGB CreditAttribution: MustangGB commented@bryanmanalo: Currently waiting on people to review and test.
Comment #64
MustangGB CreditAttribution: MustangGB commentedMinor whitespace cleanup.
Comment #65
Eric_A CreditAttribution: Eric_A commentedI've been testing group concat and group concat distinct on nid fields and other entity type id fields with #58 applied for some time. (Not sure whether #59 and #64 are basically the same. Interdiffs would help...)
Two thing I've noticed:
- link to content is broken
- I've had some issues with standard count not working (anymore?), but unrelated to this patch I guess.
Didn't have time for investigation, yet.
Comment #66
MustangGB CreditAttribution: MustangGB commented@Eric_A As per my comments the only difference between #58, #59 and #64 is a test and some whitespace cleanup, neither touch the code functionality.
Comment #67
Eric_A CreditAttribution: Eric_A commented@MustangGB, great, thanks for the update. Wasn't 100% sure if your patch in #59 was based off of #58 by lionguard (which introduced the concat distinct and removing of null) or based off of an earlier patch without the concat distinct.
What's your stand on explicitly supporting or explicitly disabling formatters or formatting options like linking to content?
Comment #68
MustangGB CreditAttribution: MustangGB commentedSeems like it might be out of scope of this issue, especially if the current aggregation methods don't support it either.
But then I'm currently using a custom solution for this sort of functionality (a context menu) so it doesn't effect me presently.
The less kittens killed the better? (lots of little patches > one mega patch)
Comment #69
scott.whittaker CreditAttribution: scott.whittaker as a volunteer commentedJust dropping a note that this doesn't work on Postgres which doesn't have a GROUP_CONCAT function.
Comment #70
jiv_e CreditAttribution: jiv_e at LilDrop Consulting commentedI have tested this with MySQL and worked for me without problems!
Comment #71
shi99 CreditAttribution: shi99 commentedPatch in #64 works for me with the latest dev version.
Thanks
Comment #72
drclaw CreditAttribution: drclaw commentedNow that #1359298: Support Plugins for Views Aggregate in D7 (D8 Backport) has been committed, GROUP_CONCAT can be achieved in a small custom module with the following code:
Perhaps this patch is no longer necessary?
Comment #73
DamienMcKennaBumping to the next release.
Comment #74
maciej.zgadzaj CreditAttribution: maciej.zgadzaj commented#72 works fine, thanks for this Chris!
Couple of notes though:
- each plugin definition in
views_aggregation_group_concat_views_plugins()
should have afile
property defined as well, if you don't want to see any PHP notices,-
GROUP_CONCAT()
is supported only by MySQL and family, so at least it should be wrapped in something likeif (in_array(Database::getConnection()->databaseType(), array('mysql', 'mysqli', 'sqlite'))) {...
. Even better if versions for other db engines are provided as well.Comment #75
DamienMcKennaRemoving this from the queue for the next release as I feel it needs a bit more consideration after #1359298: Support Plugins for Views Aggregate in D7 (D8 Backport) was committed (per #72).
Comment #76
dawehnerGiven the state of things I think a feature like this should be better worked on in core 8.x and then be backported.
Comment #77
davemaxg CreditAttribution: davemaxg commented#72 works great on 7.x-3.16. And I don't have to reapply as a patch on future updates. :)
Thanks drclaw!
Comment #78
Collins405 CreditAttribution: Collins405 commentedWhen trying to use this with views data export, i get the error....
'Exception: SQLSTATE[HY000]: General error: 1260 Row 48 was cut by GROUP_CONCAT()'
Comment #79
eott CreditAttribution: eott commentedI tried the patch for #64, but for my view, GROUP_CONCAT shows only the first item, not all the items concatenated. I have Views 7.x-3.8. Anyone else experience anything similar? It is accessing a field collection via a relationship.
Comment #80
osopolarI created the attached Drupal 7 module form @drclaw's code in #72 and implemented the suggestions from #74.
Edit:
I also created a sandbox project: https://www.drupal.org/sandbox/osopolar/views_aggregation_group_concat. If there are any issues, please post them there.
Comment #81
Chris Matthews CreditAttribution: Chris Matthews as a volunteer commentedThanks @osopolar for the module in #80. Should this feature request be closed as a "Won't fix" since #1359298: Support Plugins for Views Aggregate in D7 (D8 Backport) was committed (per #72)?
Comment #82
skylord CreditAttribution: skylord commentedMaybe we have to wait for it to be fully supported module in repository and not just a sandbox project?
Comment #83
MustangGB CreditAttribution: MustangGB commentedRe-roll of #64
Comment #84
thetwentyseven CreditAttribution: thetwentyseven commentedThe patch is great. However, I have problems trying to display concat dates.
public 'commerce_order_commerce_line_item_created' => string '1603027969, 1603025044' (length=22)
It's doing it, but in the view the field is empty. I think it's because of the format.
Comment #85
thetwentyseven CreditAttribution: thetwentyseven commentedI have recreated the #83 patch with a modification in views/handlers/views_handler_field_date.inc in order to display multiple dates with concat. I had not test it for the rest of fields.
Comment #86
thetwentyseven CreditAttribution: thetwentyseven commentedSorry I made a mistake
Comment #87
pmglondon CreditAttribution: pmglondon as a volunteer commentedYes, this patch is great!
One gotcha comes when using the GROUP_CONCAT aggregation on a numeric column that contains zeroes. In this case, the zero values are excluded from the result. That's because NULLIF(0, '') returns NULL.
Since GROUP_CONCAT ultimately outputs a string anyway, should we stringify the inputs? i.e. in
addAggregateGroupConcat
andaddAggregateGroupConcatDistinct
, replaceNULLIF($column_name, '')
withNULLIF(CAST($column_name AS CHAR), '')
.NULLIF('0', '') returns '0', so this way we retain the zeroes in the aggregated output.
Comment #88
kristofferwiklund CreditAttribution: kristofferwiklund at Websystem commented#86 patch does not apply to latest version of views.
Comment #89
ankithashettyRerolled the patch in #86 as requested in #88, thanks!