¿Por qué `GROUP BY` en hook_views_query_alter () no funciona?

11

Estoy usando Vistas 7.x-3.6 e intenté alterar la GROUP BYcláusula con hook_views_query_alter()lo siguiente:

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

Cuando miro $query, la groupbycláusula está habilitada correctamente pero la consulta SQL no se ve afectada : la GROUP BYcláusula no aparece:

ingrese la descripción de la imagen aquí

Lo que eventualmente hice fue usar un hook Drupal core ( hook_query_alter()) y funcionó bien: el SQL ahora está afectado.

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

¿Alguna razón por la cual mi hook_views_query_alter()no funciona? Me pregunto si hay una forma más limpia de hacerlo y.

jozi
fuente

Respuestas:

11

Usar add_field()con array('function' => 'groupby')parámetro.

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

Información adicional:

Después de usar add_groupby, puede ver el siguiente código después de GROUP BY:

GROUP BY node.nid, nid

Vea el próximo número: https://drupal.org/node/1578808

Para evitar condiciones innecesarias de GROUP BY, agregue:

$query->distinct = TRUE;
milkovsky
fuente
1
¿Cómo podemos eliminar el grupo innecesario sin agregar $ query-> distinct = TRUE;
ARUN
Pasé algunas horas depurando las vistas grupales. Pero actualmente no conozco otra solución.
milkovsky
Gracias por tu comentario. hmm .. estoy preguntando porque, si agregamos $ query-> distinct = TRUE; luego se agregará nidcon group by. No es necesario para mi. ¿Alguna otra opción? ¿Sabes cómo agregar consultas únicas en vistas?
ARUN
Fue una views_handler_filter::query()feria. Trate $query->distinct();enhook_query_alter
milkovsky
1

Tarde a la fiesta, pero esto podría ayudar a alguien más.

En mi caso, estaba proporcionando una lista de usuarios (usando el módulo adicional Profile2) con un campo Término de taxonomía ( https://drupal.org/node/1808320 ). Estaba viendo múltiples resultados de los que no podía deshacerme a través de la API de Views 3.

En mi módulo personalizado agregué:

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

  }
}

Los parámetros para add_field son

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

Si aún enfrenta declaraciones innecesarias de GROUP BY agregadas a la consulta, puede eliminarlas hook_query_alter(). Resolví el problema ordenando comentarios de la mayoría de los comentarios de padres comentados, por ejemplo.

Entonces en hook_views_query_alter()tengo:

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

Recibí un error relacionado con la incapacidad de agrupar por

comentarios_cuenta

campo que en realidad es el resultado de la COUNT()función SQL .

Terminé con esto:

/**
 * 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
fuente
0

Si observa la documentación de hook_views_query_alter , creo que la consulta ya está preparada para ejecutarse. Por ejemplo, la API de la base de datos ha realizado reemplazos y está a punto de enviarse por cable a MySQL. Otro ejemplo del uso de hook_views_query_alter se puede ver en el blog BTMash .

Siendo este el caso, ya no tiene un objeto de consulta de base de datos, sino las partes de la instrucción SQL con expresiones, variables, etc. como una matriz.

No tengo una consulta frente a mí, pero algo como el siguiente código no probado es lo que quieres:

$query->groupby[0]['field'] = 'field_name';
Tenken
fuente
¡Gracias por tu respuesta! Lo intenté pero tampoco funciona: de nuevo, el $queryobjeto está alterado (de forma diferente a la anterior, por supuesto), pero de nuevo, ¡la consulta SQL no cambia!
jozi
¿Probaste un gancho de vistas diferentes? _pre_render, o _pre_build? .... Intentaría hook_views_pre_execute () ... api.drupal.org/api/views/views.api.php/function/…
tenken
0

Así se hace en views_query_alter; la parte de node_access no es necesaria.

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');    
  }
}
desarrollador drupal barcelona
fuente
0

Me preguntaba que nadie proporcionaba una solución real que simplemente funcionara. Hay uno de esos métodos que he encontrado aquí , muchas gracias 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
fuente
0

En Drupal 8 y gracias al enfoque 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
fuente