This is a tutorial of creating aggregated SQL queries (the ones with a "GROUP BY" clause) in Views2. At this time, to achieve this task you must install the Views GroupBy contributed module.
Top Terms View
Views is just great most of the time, but sometimes, for complex queries, it falls short. Not all SQL queries can be represented even with a query builder as sophisticated as Views2. One of the things you used to not be able to build was an aggregate query. It's a query when you want to group fields by some criteria and run a function on the group. For instance: group nodes by term name and count how many nodes are in each group. This is a query for Term Frequency.
Real-life example: List top 10 most frequent terms applied to a specific node type and the number of nodes for each term.
Building such view used to be impossible with Views2, unless you wrote some glue code. Not anymore. Following is a step-by-step configuration instructions for building term frequency view. Similar aggregated queries can be built in almost identical way.
- Create a new Node View
- Add following fields:
- Taxonomy: Term Term
- Taxonomy: Vocabulary Name
- Node: Nid Nid (and rename its label to Nid Count)
- SQL Aggregation: Group By Fields Group By Fields (must be last field!)
- Add a field named "SQL Aggregation: Group By Fields" and configure its settings as follows:
- Fields to Group On = 'Taxonomy: Term' and 'Taxonomy: Vocabulary Name' (both fields)
- SQL Aggregation Function = Count
- Fields to Aggregate with the SQL function = Node: Nid
- Field to Sort Resultset On (after SQL Function is applied) = Node: Nid
- Sorting Direction: Descending
- Add a filtering criteria for the node type if you need to.
Which will produce the following SQL:
SELECT COUNT(node.nid) AS nid,
term_data.name AS term_data_name,
vocabulary.name AS vocabulary_name,
'term_frequency:page_1' AS view_name
FROM node node
LEFT JOIN term_node term_node ON node.vid = term_node.vid
LEFT JOIN term_data term_data ON term_node.tid = term_data.tid
LEFT JOIN vocabulary vocabulary ON term_data.vid = vocabulary.vid
GROUP BY term_data_name, vocabulary_name, term_data_name, vocabulary_name, view_name
ORDER BY nid DESC
which is almost an ideal query for the task, granted that we are using a cross-database query builder and it has some natural limitations.
The output of the given query may look something like when rendered with HTML List display plugin:
Term: gaza
Nid Count: 272
Vocabulary: Yahoo Terms
Term: israel
Nid Count: 126
Vocabulary: Yahoo Terms
Term: news articles
Nid Count: 88
Vocabulary: Yahoo Terms
Term: new york times
Nid Count: 50
Vocabulary: Yahoo Terms
Term: hamas
Nid Count: 47
Vocabulary: Yahoo Terms
Term: humanitarian crisis
Nid Count: 44
Vocabulary: Yahoo Terms
Term: financial crisis
Nid Count: 43
Vocabulary: Yahoo Terms
and of course you can theme the result-set any way you want using usual Views2 theming techniques.
Most Active FeedAPI Feeds View
Brief description of the approach:
- Let's assume your feed items have node type "feeditem"
- Create a view filtered by "feeditem" node type
- Add a FeedAPI relationship and add "Parent Feed's nid" and its title as one of the fields
- Group by parent feed's title and nid
- aggregate (count) by the feeditem's nid
One more thing...
You can also get a nice graphical chart (bar, pie, 3d... you name it) if you install and configure another Views extension, the Views Charts module.
Pretty cool?
Comments
Problem with generated Group By
When I tried to use this module it generated a GROUP BY with an additional field on the end that broke it:
e.g. The node_vid on the end of the GROUP BY field list.
SELECT
COUNT(node.nid) AS nid,
node_data_field_contractor.field_contractor_nid AS node_data_field_contractor_field_contractor_nid,
node_data_field_contractor.delta AS node_data_field_contractor_delta,
node.type AS node_type,
node.vid AS node_vid
FROM node node
LEFT JOIN content_field_contractor node_data_field_contractor
ON node.vid = node_data_field_contractor.vid
WHERE node.type IN('enquiry')
GROUP BY node_data_field_contractor_field_contractor_nid, node_data_field_contractor_delta, node_type, node_vid
ORDER BY node_data_field_contractor_field_contractor_nid DESC
patch for broken groupby
The extra fields that groupby is generating were also noted in this thread:
http://drupal.org/node/651546
and a patch that works (for me at least) is here:
http://drupal.org/node/651546#comment-2467362
grouping without need for an aggregate function
The Views Group By module is useful not only in the cases where all you want out of the view is a count but also for general Group By clause needs. You just have to throw away the output of the sum() function.
I have an Ubercart checkout screen, and on it, I am displaying all Orders for the current user along with all order details (node product title, product download links). The issue I was running into without some Group By clause is that the Order Id was repeating for each node represented in the cart.. Views Group By helped me to solve this by Group On Order Id, Aggregate with SQL Function on Order Creation Date. However, this shows Dec 1969 for all order dates... So I tossed in an additional Order Creation Date field (referred to as [created_1] in my Order By rewritten field), and life was good again.
--
http://drupaltees.com
80s themed Drupal T-Shirts
If you just want to 'group' your results
If you just want to 'group' and list your results by criteria (say day, author or tag), you don't need views_groupby.
This is available in Views already, but not in 'Filter or 'Sort' where you may look for it - it's in the setting for "Style" in the "Basic Settings". There you can find a way to define a "Grouping Field"
.dan. is the New Zealand Drupal Developer working on Government Web Standards
The built-in Views Group feature was not applicable for me
"For some reason" (yes, I wish I had taken better notes or written them out here when it was fresh), the Group feature provided by Views was just not doing it for me. I think it rewrote some output, making assumptions for me that I didn't need.. I don't recall at the moment. I just know this module saved the day!
To the previous responder: Again, I took horrible notes and have no intentions of looking back at this project I'm referring to until I'm old and grey and need a good cry! Maybe I will though..
--
http://drupaltees.com
80s themed Drupal T-Shirts
Theme Developer
For those of you having a problem with grouping in Views you may want to turn off Theme Developer if you have it enabled...
See: http://drupal.org/node/483080
Also: http://drupal.org/node/361298
Figured I'd post this here, since I wish I'd seen that first thread a couple of hours ago.
Thanks dman - totally forgot
Thanks dman - totally forgot about this.
thanks
You are absolutely right. I've also forgot about that ;)
Strony www Bydgoszcz
not the same thing
I just tried out your suggestion to use the built-in Views functionality, but the grouping in views is not the same as using a mysql "GROUP BY". Views grouping doesn't change the sql query. It only affects how the output is formatted. This module changes the sql query in order affect the results returned. Exactly what I was looking for.
A bit about mysql GROUP BY
http://www.w3schools.com/sql/sql_groupby.asp
grouping cck fields
Hi,
I am trying to group the cck field (Type : Select list) but it seems its not working or
might be I am missing something.
Below is my sql code (generated by view)
SELECT COUNT(node.nid) AS nid,
node.type AS node_type,
node_data_field_type.field_type_value AS node_data_field_type_field_type_value,
node.vid AS node_vid
FROM node node
LEFT JOIN content_type_project node_data_field_type ON node.vid = node_data_field_type.vid
GROUP BY node_data_field_type_field_type_value, node_type, node_vid
ORDER BY nid ASC
In the result each node comes as separate unique item and they are not getting group by cck field for
some reason. Any help is highly appreciated.
This is due to CCK's join on the node table
Hi Chetan
Not sure if you're still on this issue since your comment happens to be exactly one year old, but here are a few thoughts.
I'm having the same problem. Apparently the reason is that, when manipulating CCK fields, node.vid is added to the query in order to perform a JOIN. Group_by then adds this node.vid to the list of fields in the GROUP BY clause, which causes each node to appear as a distinct item.
I don't exactly know how to handle this, maybe group_by should avoid putting the JOINed fields in the GROUP BY clause - but this may not work all the time. I will file an issue in case further developments are made to this module one day.
Regards
Antoine
$sql = s/node.vid AS/NULL AS/g
Antoine:
I found a hacky workaround to get the appearance of node.vid from screwing up the aggregation in the SQL statement.
I am going to write some hook_views_query_alter() code to change the occurrence of node.vid in the SELECT list to NULL. The GROUP BY clause will effectively ignore the column then, and the COUNT() will evaluate as expected.
Seems a shame to have to write a module to fix a query, but it is what it is.
Stand by for my example.
-b
Thank you!
Thank you a million times over! This little module was a real time saver for me.
grouping view2 not working properly....
SELECT node.nid AS nid,
node_data_field_from.field_from_nid AS node_data_field_from_field_from_nid,
node.type AS node_type,
node.vid AS node_vid,
node_data_field_to.field_to_nid AS node_data_field_to_field_to_nid,
node_data_field_vehicle_number.field_vehicle_number_value AS node_data_field_vehicle_number_field_vehicle_number_value,
node.created AS node_created,
node_data_field_delivery.field_delivery_value AS node_data_field_delivery_field_delivery_value
FROM node node
INNER JOIN content_type_challan node_data_field_delivery ON node.vid = node_data_field_delivery.vid
LEFT JOIN content_field_from node_data_field_from ON node.vid = node_data_field_from.vid
LEFT JOIN content_field_to node_data_field_to ON node.vid = node_data_field_to.vid
LEFT JOIN content_type_challan node_data_field_vehicle_number ON node.vid = node_data_field_vehicle_number.vid
WHERE (node.status <> 0) AND (node.type in ('challan')) AND (node.nid IN (772,773,618,818,6852,940,6855,771,869,770,768,767,766,86751082)) AND (node_data_field_delivery.field_delivery_value = 'Dispatched')";
ORDER BY node_created DESC
bug is:
Group By only node_data_field_vehicle_number,node_created
node_data_field_from.field_from_nid AS node_data_field_from_field_from_nid,
node.type AS node_type,
node.vid AS node_vid,
node_data_field_to.field_to_nid AS node_data_field_to_field_to_nid,
node_data_field_vehicle_number.field_vehicle_number_value AS node_data_field_vehicle_number_field_vehicle_number_value
grouping view2 not working properly....
SELECT node.nid AS nid,
node_data_field_from.field_from_nid AS node_data_field_from_field_from_nid,
node.type AS node_type,
node.vid AS node_vid,
node_data_field_to.field_to_nid AS node_data_field_to_field_to_nid,
node_data_field_vehicle_number.field_vehicle_number_value AS node_data_field_vehicle_number_field_vehicle_number_value,
node.created AS node_created,
node_data_field_delivery.field_delivery_value AS node_data_field_delivery_field_delivery_value
FROM node node
INNER JOIN content_type_challan node_data_field_delivery ON node.vid = node_data_field_delivery.vid
LEFT JOIN content_field_from node_data_field_from ON node.vid = node_data_field_from.vid
LEFT JOIN content_field_to node_data_field_to ON node.vid = node_data_field_to.vid
LEFT JOIN content_type_challan node_data_field_vehicle_number ON node.vid = node_data_field_vehicle_number.vid
WHERE (node.status <> 0) AND (node.type in ('challan')) AND (node.nid IN (772,773,618,818,6852,940,6855,771,869,770,768,767,766,86751082)) AND (node_data_field_delivery.field_delivery_value = 'Dispatched')";
ORDER BY node_created DESC
bug is:
Group By only node_data_field_vehicle_number,node_created
node_data_field_from.field_from_nid AS node_data_field_from_field_from_nid,
node.type AS node_type,
node.vid AS node_vid,
node_data_field_to.field_to_nid AS node_data_field_to_field_to_nid,
node_data_field_vehicle_number.field_vehicle_number_value AS node_data_field_vehicle_number_field_vehicle_number_value
Problems with multiple languages
This issue has been moved to the Issues section: http://drupal.org/node/1142074