Comment db_select DISTINCT sur un domaine particulier dans Drupal 7?

7

Je comprends que vous pouvez spécifier -> distinct () sur l'instruction db_select afin qu'elle ne renvoie que des valeurs distinctes lorsque vous regardez TOUS les champs. Mais ce que je veux, c'est retourner des valeurs distinctes en ne regardant qu'un seul champ. Voici mon code:

$event_table = db_select('my_table', 'e')
    ->distinct()
    ->orderBy('e.time', 'ASC');//ORDER BY
$event_table->join('node', 'n', 'e.nid = n.nid'); //JOIN node with events
$event_table->groupBy('e.time');//GROUP BY time
$event_table->fields('e')//SELECT the fields from events
    ->fields('n',array('type','status','title'))//SELECT the fields from node
    ->orderBy('e.time', 'ASC');//ORDER BY

$result_event_table = $event_table->execute();
$result_event_table = $result_event_table->fetchAllAssoc('time');

Supposons que je veuille que la colonne distincte soit e.nid. On pourrait penser que -> distinct ('e.nid') fonctionnerait mais il renvoie toujours des valeurs distinctes basées sur tous les champs (c'est-à-dire distinct (colonnes1, colonne2, colonne3, etc.).

CHRIS
la source
1
Avez-vous une chance de donner un échantillon du SQL de sortie que vous recherchez? Cela rendrait assez facile de trouver comment convaincre de db_selectfaire de même
Clive

Réponses:

12

En supposant que vous essayez d'accéder à peu près à cette requête:

SELECT DISTINCT e.nid AS nid, e.time AS time, n.type AS type, n.status AS status, n.title AS title
FROM 
{my_table} e
INNER JOIN {node} n ON n.nid = e.nid
GROUP BY e.time
ORDER BY e.time ASC

Vous utiliseriez:

$query = db_select('my_table', 'e')
  ->distinct()
  ->fields('e', array('nid', 'time', 'foo', 'bar'))
  ->fields('n', array('type', 'status', 'title'))
  ->groupBy('e.time')
  ->orderBy('e.time');

$query->join('node', 'n', 'n.nid = e.nid');
Clive
la source
Cela me donne juste tous les champs distincts, pas seulement nid étant distinct
CHRIS
Je ne sais pas ce que vous voulez dire, ce qui précède est une requête distincte ... quel SQL essayez-vous de produire?
Clive
1
supposons qu'il y ait '4' '4' '5' '5' dans la colonne nid avec une colonne correspondante nommée 'type' avec 'a' 'b' 'c' 'd'. eh bien, si je sélectionne distinct sur les deux colonnes (nid, type), le résultat aura 4 lignes. mais si je sélectionne distinct sur JUST nid, le résultat aura 2 lignes. J'essaie de sélectionner distinct sur JUST nid
CHRIS
2
Je pense que vous ne comprenez pas comment fonctionne le regroupement en SQL ... pour faire ce que vous décrivez, vous devez supprimer la colonne type des champs sélectionnés
Clive
7

DISTINCT est en fait un post-modificateur global pour SELECT, c'est-à-dire que, contrairement à SELECT ALL (renvoyant toutes les réponses), c'est SELECT DISTINCT (renvoyant toutes les réponses uniques). Un seul DISTINCT agit donc sur TOUTES les colonnes que vous lui donnez.

Cela rend très difficile l'utilisation de DISTINCT sur une seule colonne, tout en obtenant les autres colonnes, sans effectuer de backflips extrêmement moche.

La bonne réponse consiste à utiliser un GROUP BY sur les colonnes pour lesquelles vous souhaitez avoir des réponses uniques:

TBI Infotech
la source
Exactement. C'est pourquoi DBTNG l'a au niveau de la requête. La seule fois où DISTINCT est au niveau de la colonne (ou y ressemble vaguement), c'est quand vous le faites, COUNT(DISTINCT foo)mais même alors, c'est un modificateur de la fonction d'agrégation.
2

Retirez-le ->distinct()et remplacez-le par$event_table->AddExpression('distinct e.nid', 'nid');

Ainsi:

$event_table = db_select('my_table', 'e');
$event_table->AddExpression('distinct e.nid', 'nid')
$event_table->orderBy('e.time', 'ASC');//ORDER BY
$event_table->join('node', 'n', 'e.nid = n.nid'); //JOIN node with events
$event_table->groupBy('e.time');//GROUP BY time

// you need to outline all fields here, can't use e.*
$event_table->fields('e')//SELECT the fields from events

    ->fields('n',array('type','status','title'))//SELECT the fields from node
    ->orderBy('e.time', 'ASC');//ORDER BY

$result_event_table = $event_table->execute();
$result_event_table = $result_event_table->fetchAllAssoc('time');
Scott Joudry
la source
PDOException: SQLSTATE [42000]: erreur de syntaxe ou violation d'accès: 1064 Vous avez une erreur dans votre syntaxe SQL; consultez le manuel correspondant à la version de votre serveur MySQL pour la syntaxe appropriée à utiliser près de 'distinct e.nid AS nid FROM mcc_notify_event_queue e INNER JOIN node n ON e.nid' à la ligne 1: SELECT e. *, n.type AS type , n.status AS status, n.title AS title, distinct e.nid AS anid FROM {mcc_notify_event_queue} e INNER JOIN {node} n ON e.nid = n.nid GROUP BY e.time ORDER BY e.time ASC; Array ()
CHRIS
ne peut pas utiliser e. * et e.nid distinct, génère une erreur. Vous devrez écrire vos champs comme je l'ai noté ci-dessus.
Scott Joudry
Je reçois toujours une erreur. Tout ce que j'ai fait, c'est changer votre code en $ event_table-> fields ('e', array ('nid', 'time', 'event_type')) // SELECT les champs des événements
CHRIS
vous sélectionnez toujours deux fois nid dans ce cas, ce qui explique l'erreur. Essayez $ event_table-> fields ('e', array ('time', 'event_type'))
Scott Joudry
toujours une erreur distincte e.nid AS nid FROM my_module_event_queue e INNER JOIN node n ON e.nid 'à la ligne 1: SELECT e.time AS time, e.event_type AS event_type, n.type AS type, n.status AS status, n.title AS title, distinct e.nid AS nid FROM {my_module_event_queue} e INNER JOIN {node} n ON e.nid = n.nid GROUP BY e.time ORDER BY e.time ASC;
CHRIS
-1

Si vous utilisez cette requête, elle fournit une requête distincte appropriée.

<?php  

$select = db_select('service_payment_transaction','o');
$select->distinct('o.transaction_id');
$select->innerJoin('users', 'u', 'u.uid = o.user_id');
$select->fields('o');
$select->fields('u');
$select->condition('o.service_gv_code','','!=');
$select->range($start,$page_count);
$select->groupBy('o.service_gv_code');
$select->orderBy('transaction_id', 'DESC');
$result_query = $select->execute();
priyank
la source
1
La fonction distincte prend un booléen comme argument, pas une chaîne.
Felix Eve