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.

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;

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'))

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

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';

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

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

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');
    }
  }
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.