Pourquoi `GROUP BY` dans hook_views_query_alter () ne fonctionne pas?

11

J'utilise Views 7.x-3.6 et j'ai essayé de modifier la GROUP BYclause avec hook_views_query_alter()comme ci-dessous:

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

Quand je regarde dedans $query, la groupbyclause est correctement activée mais la requête SQL n'est pas affectée : la GROUP BYclause n'apparaît pas:

entrez la description de l'image ici

Ce que j'ai finalement fait, c'est utiliser un core core Drupal ( hook_query_alter()) et cela a bien fonctionné: le SQL est maintenant affecté.

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

Une raison pour laquelle mon hook_views_query_alter()ne fonctionne pas? Je me demande s'il y a une façon plus propre de le faire et.

jozi
la source

Réponses:

11

Utiliser add_field()avec array('function' => 'groupby')paramètre.

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

Informations supplémentaires:

Après utilisation, add_groupbyvous pourriez voir le code suivant après GROUP BY:

GROUP BY node.nid, nid

Voir le prochain numéro: https://drupal.org/node/1578808

Pour éviter les conditions GROUP BY inutiles, ajoutez:

$query->distinct = TRUE;
milkovsky
la source
1
Comment supprimer un groupe inutile sans ajouter $ query-> distinct = TRUE;
ARUN
J'ai passé quelques heures à déboguer des vues par groupe. Mais actuellement je ne connais pas d'autre solution.
milkovsky
Merci pour votre commentaire. hmm .. je demande parce que, si nous ajoutons $ query-> distinct = TRUE; puis il ajoutera nidavec group by. Ce n'est pas nécessaire pour moi. Une autre option? Savez-vous comment ajouter une requête unique dans les vues?
ARUN
C'était une views_handler_filter::query()foire. Essayez $query->distinct();danshook_query_alter
milkovsky
1

Tard dans la soirée mais cela pourrait aider quelqu'un d'autre.

Dans mon cas, je fournissais une liste d'utilisateurs (en utilisant le module supplémentaire Profile2) avec un champ de terme de taxonomie ( https://drupal.org/node/1808320 ). Je voyais plusieurs résultats dont je ne pouvais pas me débarrasser via l'API Views 3.

Dans mon module personnalisé, j'ai ajouté:

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

  }
}

Les paramètres pour add_field sont

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

Si vous rencontrez toujours des instructions GROUP BY inutiles ajoutées à la requête, vous pouvez les supprimer hook_query_alter(). J'ai résolu le problème de la commande des commentaires par la plupart des commentaires des parents commentés par exemple.

Donc, hook_views_query_alter()j'ai:

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

J'ai une erreur liée à l'impossibilité de regrouper par

comments_count

champ qui est en fait le résultat de la COUNT()fonction SQL .

Je me suis retrouvé avec ceci:

/**
 * 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
la source
0

Si vous regardez la documentation de hook_views_query_alter , je pense que la requête est déjà prête à s'exécuter. Par exemple, des remplacements ont été effectués par l'API de base de données et sont sur le point d'être envoyés par câble à MySQL. Un autre exemple d'utilisation de hook_views_query_alter peut être vu sur le blog BTMash .

Cela étant, vous n'avez plus d'objet de requête DB, mais les éléments de l'instruction SQL avec des expressions, des variables, etc. sous forme de tableau.

Je n'ai pas de requête devant moi mais quelque chose comme le code non testé suivant est ce que vous voulez:

$query->groupby[0]['field'] = 'field_name';
tenken
la source
Merci pour votre réponse! J'ai essayé mais ça ne marche pas non plus: encore une fois, l' $queryobjet est modifié (différemment de ce qui précède bien sûr) mais encore une fois, la requête SQL ne change pas!
jozi
avez-vous essayé un point de vue différent? _pre_render ou _pre_build? .... J'essaierais hook_views_pre_execute () ... api.drupal.org/api/views/views.api.php/function/…
tenken
0

C'est ainsi que cela se fait dans views_query_alter; la partie node_access n'est pas nécessaire.

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');    
  }
}
développeur drupal barcelone
la source
0

Je me suis demandé que personne ne fournissait une vraie solution qui fonctionne. Il y a une telle méthode que j'ai trouvée ici , merci beaucoup à @ 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
la source
0

Dans Drupal 8 et grâce à l'approche graceman9, ce sera:

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
la source