Por que `GROUP BY` em hook_views_query_alter () não funciona?

11

Estou usando as Views 7.x-3.6 e tentei alterar a GROUP BYcláusula da hook_views_query_alter()seguinte forma:

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

Quando olho para dentro $query, a groupbycláusula está ativada corretamente, mas a consulta SQL não é afetada : a GROUP BYcláusula não aparece:

insira a descrição da imagem aqui

O que finalmente fiz foi usar um núcleo hook do Drupal ( hook_query_alter()) e funcionou bem: o SQL agora é afetado.

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

Alguma razão para o meu hook_views_query_alter()não funcionar? Gostaria de saber se existe uma maneira mais limpa de fazê-lo e.

jozi
fonte

Respostas:

11

Use add_field()com o array('function' => 'groupby')parâmetro

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

Informações adicionais:

Após o uso, add_groupbyvocê poderá ver o próximo código após GROUP BY:

GROUP BY node.nid, nid

Veja a próxima edição: https://drupal.org/node/1578808

Para evitar condições GROUP BY desnecessárias, adicione:

$query->distinct = TRUE;
milkovsky
fonte
1
Como podemos remover um grupo desnecessário sem adicionar $ query-> distinct = TRUE;
ARUN
Passei algumas horas depurando visualizações de grupo por. Mas atualmente não conheço outra solução.
milkovsky
Obrigado por seu comentário. hmm .. estou perguntando porque, se adicionarmos $ query-> distinct = TRUE; depois será adicionado nidcom o grupo por. Não é necessário para mim. Alguma outra opção? Você sabe como adicionar uma consulta exclusiva nas visualizações?
ARUN
Foi views_handler_filter::query()justo. Tente $query->distinct();emhook_query_alter
milkovsky
1

Tarde para a festa, mas isso pode ajudar outra pessoa.

No meu caso, eu estava fornecendo uma lista de usuários (usando o módulo adicional Profile2) com um campo Termo de taxonomia ( https://drupal.org/node/1808320 ). Eu estava vendo vários resultados dos quais não consegui me livrar da API do Views 3.

No meu módulo personalizado, adicionei:

/**
    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'));

  }
}

Os parâmetros para add_field são

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

Se você ainda estiver enfrentando instruções GROUP BY desnecessárias adicionadas à consulta, poderá removê-las hook_query_alter(). Resolvi o problema solicitando comentários pelos comentários dos pais mais comentados, por exemplo.

Então, hook_views_query_alter()eu tenho:

/**
 * 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]);
  }
}

Recebi um erro relacionado à incapacidade de agrupar por

comments_count

campo que é realmente um resultado da COUNT()função SQL .

Eu acabei com isso:

/**
 * 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]);
      }
    }
  }
}
Dmitriy
fonte
0

Se você procurar a documentação de hook_views_query_alter , acredito que a consulta já esteja preparada para executar. Por exemplo, substituições foram feitas pela API do banco de dados e estão prestes a ser enviadas pelo MySQL. Outro exemplo de uso de hook_views_query_alter pode ser visto no blog do BTMash .

Sendo esse o caso, você não possui mais um Objeto de Consulta ao Banco de Dados, mas as partes da instrução SQL com expressões, variáveis, etc. como uma Matriz.

Eu não tenho uma consulta na minha frente, mas algo como o seguinte código não testado é o que você deseja:

$query->groupby[0]['field'] = 'field_name';
tenken
fonte
Obrigado pela sua resposta! Tentei, mas também não funciona: novamente, o $queryobjeto é alterado (diferentemente do que foi dito acima), mas novamente, a consulta SQL não muda!
jozi 20/05
você tentou um gancho de vistas diferentes? _pre_render ou _pre_build? ... eu tentaria hook_views_pre_execute () ... api.drupal.org/api/views/views.api.php/function/…
tenken
0

É assim que é feito em views_query_alter; a parte node_access não é necessária.

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');    
  }
}
drupal developer barcelona
fonte
0

Gostaria de saber que ninguém forneceu uma solução real que simplesmente funcionasse. Existe um método que eu encontrei aqui , muito obrigado a @ 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');
    }
  }
}
graceman9
fonte
0

No Drupal 8 e, graças à abordagem graceman9, será:

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');
    }
  }
}
romain ni
fonte