I have a custom module that provides a default view. The view has an argument, set to display a summary (with record count) very similar to the archive view. What I've noticed is that the SQL generated always has the the COUNT(DISTINCT(records)), as opposed to only COUNT(records).
Before posting my views/SQL query, I wanted to see if this could possibly be a bug... In query.inc, note that the check for a distinct field uses an isset()
:
function query($get_count = FALSE) {
...
if (isset($field['distinct'])) {
$string = "DISTINCT($string)";
}
...
An argument of User: Name, use the views_handler_argument.inc
which has the following:
function summary_basics($count_field = TRUE) {
...
$distinct = ($this->view->display_handler->get_option('distinct') && empty($this->query->no_distinct));
...
$distinct
, or more specifically, the $this->view->display_handler->get_option('distinct')
in this case returns FALSE, which when put through an isset()
like the one from query.inc will return TRUE, which will then result in the "DISTINCT" function being added to the query. Looking closer at the function get_option()
, it seems is where the FALSE return is being generated.
As for a fix, I'm not sure whether it makes sense to remove the isset() and replace it with a more vanilla boolean check (probably not but that what the attached patch does), or if we should just make sure to pass NULL, instead of FALSE, if we don't want a distinct to be added to the query. I guess the other option is to have view->display_handler->get_option('distinct')
return NULL, and not FALSE.
Now for the views, and SQL:
$view = new view;
$view->name = 'testing';
$view->description = '';
$view->tag = '';
$view->view_php = '';
$view->base_table = 'sa_reporting';
$view->is_cacheable = FALSE;
$view->api_version = 2;
$view->disabled = FALSE; /* Edit this to true to make a default view disabled initially */
$handler = $view->new_display('default', 'Defaults', 'default');
$handler->override_option('fields', array(
'timestamp' => array(
'label' => 'Date of the view',
'alter' => array(
'alter_text' => 0,
'text' => '',
'make_link' => 0,
'path' => '',
'alt' => '',
'prefix' => '',
'suffix' => '',
'help' => '',
'trim' => 0,
'max_length' => '',
'word_boundary' => 1,
'ellipsis' => 1,
'html' => 0,
),
'date_format' => 'small',
'custom_date_format' => '',
'exclude' => 0,
'id' => 'timestamp',
'table' => 'sa_reporting',
'field' => 'timestamp',
'relationship' => 'none',
),
'nid' => array(
'label' => 'Nid',
'alter' => array(
'alter_text' => 0,
'text' => '',
'make_link' => 0,
'path' => '',
'alt' => '',
'prefix' => '',
'suffix' => '',
'help' => '',
'trim' => 0,
'max_length' => '',
'word_boundary' => 1,
'ellipsis' => 1,
'html' => 0,
),
'link_to_node' => 0,
'exclude' => 0,
'id' => 'nid',
'table' => 'node',
'field' => 'nid',
'relationship' => 'none',
),
));
$handler->override_option('arguments', array(
'name' => array(
'default_action' => 'summary asc',
'style_plugin' => 'default_summary',
'style_options' => array(
'count' => 1,
'override' => 0,
'items_per_page' => '25',
),
'wildcard' => 'all',
'wildcard_substitution' => 'All',
'title' => '',
'default_argument_type' => 'fixed',
'default_argument' => '',
'validate_type' => 'none',
'validate_fail' => 'not found',
'glossary' => 0,
'limit' => '0',
'case' => 'none',
'path_case' => 'none',
'transform_dash' => 0,
'id' => 'name',
'table' => 'users',
'field' => 'name',
'relationship' => 'none',
'default_options_div_prefix' => '',
'default_argument_user' => 0,
'default_argument_fixed' => '',
'default_argument_php' => '',
'validate_argument_node_type' => array(
'page' => 0,
'story' => 0,
),
'validate_argument_node_access' => 0,
'validate_argument_nid_type' => 'nid',
'user_argument_type' => '',
'restrict_user_roles' => 0,
'user_roles' => array(),
'validate_argument_php' => '',
),
));
$handler->override_option('access', array(
'type' => 'none',
));
$handler->override_option('style_plugin', 'table');
$handler->override_option('style_options', array(
'grouping' => '',
'override' => 1,
'sticky' => 0,
'order' => 'asc',
'columns' => array(
'timestamp' => 'timestamp',
'nid' => 'nid',
),
'info' => array(
'timestamp' => array(
'sortable' => 0,
'separator' => '',
),
'nid' => array(
'sortable' => 0,
'separator' => '',
),
),
'default' => '-1',
));
$handler = $view->new_display('page', 'Page', 'page_1');
$handler->override_option('path', 'asdf');
$handler->override_option('menu', array(
'type' => 'none',
'title' => '',
'description' => '',
'weight' => 0,
'name' => 'navigation',
));
$handler->override_option('tab_options', array(
'type' => 'none',
'title' => '',
'description' => '',
'weight' => 0,
));
SQL:
SELECT users.name AS users_name,
COUNT(DISTINCT(sa_reporting.nid)) AS num_records
FROM sa_reporting sa_reporting
LEFT JOIN node node ON sa_reporting.nid = node.nid
LEFT JOIN users users ON node.uid = users.uid
GROUP BY users_name
ORDER BY users_name ASC
If anyone else is facing a similar problem, the workaround I used was to create a custom argument handler, and overrode, function summary_basics
and changed this:
...
$count_alias = $this->query->add_field(NULL, $field, 'num_records',
array('count' => TRUE, 'distinct' => $distinct));
..
To look like this:
...
$count_alias = $this->query->add_field(NULL, $field, 'num_records',
array('count' => TRUE, 'distinct' => NULL));
...
Comment | File | Size | Author |
---|---|---|---|
#2 | distinct_followup.patch | 665 bytes | David_Rothstein |
distinct.patch | 628 bytes | bcn | |
Comments
Comment #1
merlinofchaos CreditAttribution: merlinofchaos commentedThis should use !empty() rather than a simple boolean check; the simple boolean check can cause notices. Otherwise I believe this is likely the correct fix.
Committed.
Comment #2
David_Rothstein CreditAttribution: David_Rothstein commentedI came across this while trying to help someone at #375298: Pager misses records when multiple value fields are displayed with other fields. It looks to me like there is actually one more case of isset() vs !empty() in the same function that was missed in the above commit.
A followup patch is attached. It should be pretty trivial, but those are famous last words :)... The effect of the patch should be that the count_query will now be optimized in situations where it was needlessly un-optimized before.
Comment #3
merlinofchaos CreditAttribution: merlinofchaos commentedCommitted! Thanks!