为什么hook_views_query_alter()中的“ GROUP BY”不起作用?


11

我正在使用Views 7.x-3.6,并尝试通过以下方式更改GROUP BY子句hook_views_query_alter()

function mymodule_views_query_alter(&$view, &$query) {
    if ($view->name == "view_name"){
      $query->add_groupby('field_name');
      dpm($query);    
    }
}

当我查看时$querygroupby子句已正确启用,SQL查询不受影响:该GROUP BY子句未出现:

在此处输入图片说明

我最终做的是使用Drupal核心钩子(hook_query_alter()),它运行良好:SQL现在受到影响。

function mymodule_query_alter(QueryAlterableInterface $query) {
  $view_name = 'view_name';
  if ($query->hasTag('views_' . $view_name)) {    
    $query->groupBy('field_name');
  }
}

有什么原因导致我hook_views_query_alter()无法正常工作?我想知道是否有更清洁的方法来做到这一点。

Answers:


11

add_field()array('function' => 'groupby')参数一起使用。

$query->add_field('node', 'nid', 'node_nid', array('function' => 'groupby'));
$query->add_groupby('node.nid');

附加信息:

使用后,add_groupby您可能会在下面看到以下代码GROUP BY

GROUP BY node.nid, nid

请参阅下一个问题:https : //drupal.org/node/1578808

为避免不必要的GROUP BY条件,请添加:

$query->distinct = TRUE;

1
我们如何通过不添加$ query-> distinct = TRUE来删除不必要的组;
2014年

我花了几个小时来调试视图分组依据。但目前我不知道其他解决方案。
milkovsky 2014年

谢谢你的评论。嗯..我问是因为,如果我们加上$ query-> distinct = TRUE; 然后它将nid与分组依据添加。对我来说没有必要。还有其他选择吗?您知道如何在视图查询中添加唯一性吗?
2014年

这很views_handler_filter::query()公平。尝试$query->distinct();hook_query_alter
milkovsky

1

晚会晚了,但这可能对其他人有帮助。

在我的情况下,我正在为用户列表(使用附加模块Profile2)提供一个分类术语字段(https://drupal.org/node/1808320)。我看到无法通过Views 3 API摆脱​​的多个结果。

在我的自定义模块中,我添加了:

/**
    Implementation of hook_views_query_alter()
**/
function MYMODULE_views_query_alter(&$view, &$query) {

  if($view->name == "provider_results_list" && $view->current_display == "page_1") {

    $query->distinct = TRUE;

    // User the provider uid to make the results distinct: using a taxonomy field for
    // keyword searches brings up multiple results. 
    $query->add_field('profile', 'uid', 'provider_uid', array('function' => 'groupby'));

  }
}

add_field的参数是

add_field(TABLE_NAME, FIELD, FIELD_ALIAS, array('function' => 'groupby'))

1

如果您仍然面临不必要的GROUP BY语句添加到查询中,则可以在中将其删除hook_query_alter()。我通过按评论最多的父评论排序评论来解决此问题。

所以hook_views_query_alter()我有:

/**
 * Implements hook_views_query_alter().
 */
function MODULENAME_views_query_alter(&$view, &$query) {
  if ($view->name == 'reviews' && $query->orderby[0]['field'] == 'comment_thread') {
    $join = new views_join;
    $join->construct('comment', 'comment', 'cid', 'pid', NULL, 'LEFT');
    $query->add_relationship('c1', $join, 'comment');
    $query->add_field('comment', 'pid', 'c1_pid', array('function' => 'groupby'));
    $query->add_groupby('c1.pid');
    $query->add_orderby(NULL, 'COUNT(c1.cid)', 'DESC', 'comments_count');
    $query->distinct = TRUE;
    $query->orderby[0] = $query->orderby[count($query->orderby) - 1];
    unset($query->orderby[count($query->orderby) - 1]);
  }
}

我收到有关无法分组的错误

comments_count

字段,实际上是SQL COUNT()函数的结果。

我结束了这个:

/**
 * Implements hook_query_alter().
 */
function MODULENAME_query_alter(QueryAlterableInterface $query) {
  if (isset($query->alterMetaData['view']->name) && $query->alterMetaData['view']->name == 'reviews') {
    $fields =& $query->getGroupBy();
    foreach (array_keys($fields) as $key) {
      // Remove group by statements from generated query which were actually not set in view query.
      if (!in_array($key, $query->alterMetaData['view']->query->groupby)) {
        unset($fields[$key]);
      }
    }
  }
}

0

如果您查看hook_views_query_alter的文档,我相信查询已经准备好运行。例如,替换已由数据库API进行,它将通过有线方式发送到MySQL。可以在BTMash博客中看到hook_views_query_alter用法的另一个示例

在这种情况下,您将不再具有数据库查询对象,而是将带有表达式,变量等的SQL语句片段作为数组。

我前面没有查询,但是您想要的是以下未经测试的代码:

$query->groupby[0]['field'] = 'field_name';

感谢您的回答!我试过了,但是它也不起作用:再次,$query对象被更改了(与上面的过程不同),但是SQL查询没有改变!
jozi 2013年

您是否尝试了其他视图挂钩?_pre_render或_pre_build?....我会尝试hook_views_pre_execute()... api.drupal.org/api/views/views.api.php/function/…–
Tenken

0

这是在views_query_alter中完成的方式;不需要node_access部分。

function xdas_target_audience_views_query_alter(&$view, &$query) {
  $controlled_views = variable_get('xdas_target_audience_views', array(
    'landing_products',
    'promotions',
    'landing_coupons',
    'landing_coupons_belvita',
    'landing_coupons_lulu',
    'related_coupon',
    'cuponazo',
    'banner',
    'brands',
  ));
  if (in_array($view->name, $controlled_views) && $view->base_table == 'node') {
    //add node_access to views so we can control access.
    $query->add_tag('node_access');
    $join = new views_join();
    $join->construct('xdas_target_audience_boost', 'node', 'nid', 'nid');        
    $query->add_relationship('xdas_target_audience_boost', $join, 'node');
    $query->add_field('xdas_target_audience_boost', 'score', 'score' , array('function' => 'max'));
    $query->add_orderby(NULL, NULL, 'DESC', 'score');   
    $query->add_groupby('nid');    
  }
}

0

我想知道没有人提供一种真正可行的解决方案。我在这里找到一种这样的方法,非常感谢@ b-ravanbakhsh:

/**
 * Implements hook_query_alter().
 */
function MODULENAME_query_alter(QueryAlterableInterface $query) {
  if (isset($query->alterMetaData['view'])) {
    if($query->alterMetaData['view']->name == 'YOUR_VIEW_NAME'){
      // also you can unset other group by critera by using, unset($query->getGroupBy());
      $query->groupBy('users.uid');
    }
  }
}

0

在Drupal 8中,由于使用graceman9方法,它将是:

use Drupal\Core\Database\Query\AlterableInterface;

function MYMODULE_query_alter(AlterableInterface $query) {
  if (isset($query->alterMetaData['view'])) {
    if($query->alterMetaData['view']->id() == 'replace_by_view_machine_name') {
      // Group by UID to remove duplicates from View results
      $query->groupBy('users_field_data.uid');
      // If multilingual site, you should add the following
      // $query->groupBy('users_field_data.langcode');
    }
  }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.