Warum funktioniert `GROUP BY` in hook_views_query_alter () nicht?

11

Ich verwende Views 7.x-3.6 und habe versucht, die GROUP BYKlausel hook_views_query_alter()wie folgt zu ändern :

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

Wenn ich nachschaue $query, ist die groupbyKlausel korrekt aktiviert, aber die SQL-Abfrage ist nicht betroffen : Die GROUP BYKlausel wird nicht angezeigt:

Geben Sie hier die Bildbeschreibung ein

Was ich schließlich getan habe, ist die Verwendung eines Drupal-Core-Hooks ( hook_query_alter()) und es hat gut funktioniert: Das SQL ist jetzt betroffen.

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

Gibt es einen Grund, warum mein hook_views_query_alter()nicht funktioniert? Ich frage mich, ob es einen saubereren Weg gibt und.

jozi
quelle

Antworten:

11

Verwenden Sie add_field()mit array('function' => 'groupby')Parametern.

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

Zusätzliche Informationen:

Nach der Verwendung add_groupbywird möglicherweise der folgende Code angezeigt GROUP BY:

GROUP BY node.nid, nid

Siehe die nächste Ausgabe: https://drupal.org/node/1578808

Um unnötige GROUP BY-Bedingungen zu vermeiden, fügen Sie Folgendes hinzu:

$query->distinct = TRUE;
melkowski
quelle
1
Wie können wir unnötige Gruppen entfernen, indem wir $ query-> unique = TRUE hinzufügen?
ARUN
Ich habe einige Stunden damit verbracht, Ansichten von zu debuggen. Aber derzeit kenne ich keine andere Lösung.
Milkovsky
Vielen Dank für Ihren Kommentar. hmm .. ich frage weil, wenn wir $ query-> unique = TRUE hinzufügen; dann wird es nidmit group by hinzugefügt . Es ist für mich nicht notwendig. Irgendeine andere Option? Wissen Sie, wie Sie eine eindeutige Abfrage in Ansichten hinzufügen können?
ARUN
Es war views_handler_filter::query()fair. Versuchen Sie $query->distinct();inhook_query_alter
Milkovsky
1

Spät zur Party, aber das könnte jemand anderem helfen.

In meinem Fall habe ich eine Liste der Benutzer (unter Verwendung des zusätzlichen Moduls Profile2) mit einem Feld für den Taxonomiebegriff ( https://drupal.org/node/1808320 ) bereitgestellt . Ich habe mehrere Ergebnisse gesehen, die ich über die Views 3-API nicht entfernen konnte.

In meinem benutzerdefinierten Modul habe ich hinzugefügt:

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

  }
}

Die Parameter für add_field sind

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

Wenn Sie immer noch mit unnötigen GROUP BY-Anweisungen konfrontiert sind, die der Abfrage hinzugefügt wurden, können Sie diese entfernen hook_query_alter(). Ich habe das Problem gelöst, indem ich beispielsweise Kommentare von den meisten kommentierten Elternkommentaren bestellt habe.

Also in habe hook_views_query_alter()ich:

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

Ich habe einen Fehler im Zusammenhang mit der Unfähigkeit, nach zu gruppieren

comment_count

Feld, das tatsächlich ein Ergebnis der SQL- COUNT()Funktion ist.

Am Ende hatte ich Folgendes:

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

Wenn Sie sich die Dokumentation von hook_views_query_alter ansehen , ist die Abfrage meines Erachtens bereits für die Ausführung vorbereitet. Beispielsweise wurden Ersetzungen durch die Datenbank-API vorgenommen und werden bald über die Leitung an MySQL gesendet. Ein weiteres Beispiel für die Verwendung von hook_views_query_alter ist der BTMash-Blog .

In diesem Fall haben Sie kein DB-Abfrageobjekt mehr, sondern die Teile der SQL-Anweisung mit Ausdrücken, Variablen usw. als Array.

Ich habe keine Abfrage vor mir, aber so etwas wie der folgende ungetestete Code ist das, was Sie wollen:

$query->groupby[0]['field'] = 'field_name';
Tenken
quelle
Danke für deine Antwort! Ich habe es versucht, aber es funktioniert auch nicht: Auch hier wird das $queryObjekt geändert (natürlich anders als oben), aber auch hier ändert sich die SQL-Abfrage nicht!
jozi
Hast du einen anderen Views Hook ausprobiert? _pre_render oder _pre_build? .... ich würde versuchen hook_views_pre_execute () ... api.drupal.org/api/views/views.api.php/function/…
tenken
0

So wird es in views_query_alter gemacht; Der Teil node_access ist nicht erforderlich.

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 Entwickler Barcelona
quelle
0

Ich fragte mich, dass niemand eine echte Lösung lieferte, die einfach funktioniert. Es gibt eine solche Methode, die ich hier gefunden habe , vielen Dank an @ 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
quelle
0

In Drupal 8 und dank graceman9 Ansatz wird es sein:

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
quelle