Views3 e subquery?


12

Ho una vista che genera una query che fa più join. Questo produce un join cartesiano e ho bisogno di "convertire" i join in sottoquery.

Ho consultato la documentazione, i risultati di ricerca di Google e altre fonti, ma non riesco a trovare una descrizione decente di come posso configurare Views per eseguire le subquery. Ho usato hook_views_data () per configurare le relazioni (che ora vengono eseguite come join). È in qualche modo possibile definire sottoquery tramite hook_views_data () o devo adottare un altro approccio?

Qualsiasi consiglio apprezzato!

Risposte:


5

Ho guardato oltre, ma non sono riuscito a trovare alcuna documentazione che descriva questo.

Ciò di cui avevo bisogno era un modo per unire la tabella degli utenti con altre due tabelle che contenevano dati per gli utenti. Tuttavia, le altre due tabelle hanno una relazione "uno-a-molti" con la tabella degli utenti, il che significa che finirò con un join cartesiano se provo a unire la tabella degli utenti con entrambe queste tabelle contemporaneamente . Tuttavia, poiché tutto ciò di cui ho bisogno è contare il numero di record nelle altre due tabelle associate a un determinato utente, una sottoquery dovrebbe essere in grado di fare il trucco. Tuttavia, non sono riuscito a trovare documentazione su Views e sottoquery, quindi ecco cosa ho fatto.

  1. Creato due campi fittizi

Ho creato due campi fittizi (che chiamerò "download" e "ascolta") tramite hook_views_data (). La definizione del campo è elencata di seguito.

function hook_views_data() {

  $data['users'] = array(
    'downloads' => array(
      'title' => t('Downloads'),
      'field' => array(
        'handler' => 'views_handler_field_numeric',
        'click sortable' => TRUE,
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
    ),
    'listens' => array(
      'title' => t('Listens'),
      'field' => array(
        'handler' => 'views_handler_field_numeric',
        'click sortable' => TRUE,
      ),
      'filter' => array(
        'handler' => 'views_handler_filter_numeric',
      ),
      'sort' => array(
        'handler' => 'views_handler_sort',
      ),
    )
  ),
);

Ora, quando configuri una vista per gli utenti, appariranno i campi "Download" e "Ascolta". Tuttavia, il tentativo di eseguire una query ora comporterà un errore poiché i campi fittizi dopo tutto sono campi fittizi. Non esistono. L'unico scopo di questi campi è di segnalare alla nostra implementazione di hook_views_query_alter () che è necessario eseguire alcuni sostituitori.

  1. Implementa hook_views_query_alter ()

Il trucco qui è verificare se la query fornita include i campi "Download" o "Ascolta". In tal caso, rimuoveremo i campi dalla query e li sostituiremo con le subquery. L'implementazione di questa funzione è la seguente.

function mta_views_query_alter(&$view, &$query) {

  foreach ($query->fields as $field_key => &$field_values) {
    if ($field_values['table'] == 'users') {

      switch ($field_values['field']) {
        case 'downloads':
          unset($query->fields[$field_key]);
          $query->add_field(null, "(SELECT COUNT(*) FROM {fileusage} fu WHERE fu.externaluser = {users}.uid AND fu.action = 0)", $field_key);
          break;
        case 'listens':
          unset($query->fields[$field_key]);
          $query->add_field(null, "(SELECT COUNT(*) FROM {fileusage} fu WHERE fu.externaluser = {users}.uid AND fu.action = 1)", $field_key);
          break;
      }
    }
  }
}

Tieni presente che stiamo riutilizzando l'alias del campo rimosso per la sottoquery. In questo modo, Views penserà che il valore restituito dalla sottoquery provenga effettivamente dal campo fittizio (che dopotutto non esiste).

Questo è. Non stiamo ottenendo un join cartesiano e sia i "download" che gli "ascolti" vengono conteggiati correttamente.


4

Ho usato la soluzione di sbrattla fino a quando non avevo bisogno che la subquery ereditasse i valori del filtro. Ora uso il modulo views_field_view per incorporare una vista separata che esegue la query di conteggio. Posso passare i valori del filtro di contesto a quella vista incorporata tramite il modulo views_filterfield (che ho scritto) che rende disponibili i valori di filtro come campi di vista (e quindi token).

La query di conteggio ora funziona ed eredita i filtri esposti sulla query principale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.