Laravel Eloquent - distinct () et count () ne fonctionnent pas correctement ensemble


95

J'essaye donc d'obtenir le nombre de pids distincts sur une requête, mais la valeur renvoyée est fausse.

C'est ce que j'essaye de faire:

$ad->getcodes()->groupby('pid')->distinct()->count()

ce qui renvoie la valeur "2", tandis que la valeur qu'il doit renvoyer doit être "1".

Pour contourner le problème, je fais ceci:

count($ad->getcodes()->groupby('pid')->distinct()->get())

ce qui fonctionne bien et renvoie "1"

Existe-t-il une règle où count et distinct ne peuvent pas être sur la même requête? Je trouve que la solution de contournement est "lourde", je voudrais faire fonctionner la requête d'origine :(


Qu'avez-vous dans votre exemple de table dans la base de données? Et que voulez-vous accomplir? Maintenant, vous devriez probablement obtenir le nombre de valeurs distinctes dans la pidcolonne, donc si vous avez dans votre table 2 enregistrements - un avec pid 1, le second avec pid 2, count devrait renvoyer 2.
Marcin Nabiałek

vous pouvez simplement remplacer get par count de cette manière: $count = DB::table('tablename')->count(DB::raw('DISTINCT pid')); pouvez également faire: DB::table('tablename')->distinct('pid')->count('pid');
bharat

Réponses:


123

Ce qui suit devrait fonctionner

$ad->getcodes()->distinct('pid')->count('pid');

2
J'ai eu un problème similaire et il semble simplement laisser de côté le groupByfait l'affaire.
jeteon

8
Distinct n'accepte aucun argument. L'appel de distinct () lors de la construction de votre requête définit simplement le booléen protégé sur true, l'argument est ignoré.
Matt McDonald

Sur L5.1 et cela ne fonctionne toujours pas. L'utilisation count()semble désactiver ou supprimer le fichier distinct(). Utilisez groupBy()comme décrit tout au long de la question. Edit: Je trouve que même groupBy()fournit un différent count()par rapport à get()suivi en comptant le tableau résultant.
Jason

@Jason J'ai fait le même constat que toi. Voir ma réponse pour une solution.
Zoon

21
La distinct()fonction ne prend aucun argument. Vous pouvez le changer $ad->getcodes()->distinct()->count('pid');avec le même résultat.
Trevor Gehman

26

Une réponse plus générique qui m'aurait fait gagner du temps, et j'espère que d'autres:

Ne fonctionne pas (renvoie le nombre de toutes les lignes):

DB::table('users')
            ->select('first_name')
            ->distinct()
            ->count();

Le correctif:

DB::table('users')
            ->distinct()
            ->count('first_name');

17

Quelqu'un d'autre est tombé sur ce post et ne trouve pas les autres suggestions pour fonctionner?

En fonction de la requête spécifique, une approche différente peut être nécessaire. Dans mon cas, je devais soit compter les résultats d'un GROUP BY, par exemple

SELECT COUNT(*) FROM (SELECT * FROM a GROUP BY b)

ou utilisez COUNT(DISTINCT b):

SELECT COUNT(DISTINCT b) FROM a

Après quelques intrigues, j'ai réalisé qu'il n'y avait pas de fonction Laravel intégrée pour l'un ou l'autre. La solution la plus simple était donc d'utiliser l'utilisation DB::rawavec la countméthode.

$count = $builder->count(DB::raw('DISTINCT b'));

N'oubliez pas de ne pas utiliser groupByavant d'appeler count. Vous pouvez postuler groupByplus tard, si vous en avez besoin pour obtenir des lignes.


D'où vient $ builder?
Andrew

1
@Andrew Le générateur de requêtes Laravel que vous utilisez pour la requête. Par exemple, un objet éloquent$books = Book::where(...)->count(...)
Zoon

->count(DB::raw('DISTINCT b'))générer la même requête SQL que->distinct()->count('b')
Trevor Gehman

5

J'ai eu un problème similaire et j'ai trouvé un moyen de le contourner.

Le problème est la façon dont le générateur de requêtes de Laravel gère les agrégats. Il prend le premier résultat renvoyé, puis renvoie la valeur «agrégée». C'est généralement bien, mais lorsque vous combinez count avec groupBy, vous renvoyez un nombre par élément groupé. Ainsi, l'agrégat de la première ligne est juste un décompte du premier groupe (donc quelque chose de faible comme 1 ou 2 est probable).

Le décompte de Laravel est donc sorti, mais j'ai combiné le générateur de requêtes Laravel avec du SQL brut pour obtenir un décompte précis de mes résultats groupés.

Pour votre exemple, je m'attends à ce que ce qui suit fonctionne (et vous permette d'éviter le get):

$query = $ad->getcodes()->groupby('pid')->distinct();
$count = count(\DB::select($query->toSql(), $query->getBindings()));

Si vous voulez vous assurer de ne pas perdre de temps à sélectionner toutes les colonnes, vous pouvez éviter cela lors de la création de votre requête:

 $query = $ad->select(DB::raw(1))->getcodes()->groupby('pid')->distinct();

4

J'ai rencontré le même problème.

Si vous installez la barre de débogage laravel, vous pouvez voir les requêtes et voir souvent le problème

$ad->getcodes()->groupby('pid')->distinct()->count()

changer en

$ad->getcodes()->distinct()->select('pid')->count()

Vous devez définir les valeurs à renvoyer comme distinctes. Si vous ne définissez pas les champs de sélection, toutes les colonnes de la base de données seront renvoyées et toutes seront uniques. Définissez donc la requête sur distinct et ne sélectionnez que les colonnes qui constituent votre valeur `` distincte '' que vous voudrez peut-être en ajouter. ->select('pid','date')pour obtenir toutes les valeurs uniques d'un utilisateur en une journée


4

Vous pouvez utiliser la méthode suivante pour obtenir les données uniques selon vos besoins, comme suit,

$data = $ad->getcodes()->get()->unique('email');

$count = $data->count();

J'espère que cela fonctionnera.


1

Cela ne fonctionnerait-il pas?

$ad->getcodes()->distinct()->get(['pid'])->count();

Voir ici pour discussion.


3
Ce n'est pas une bonne solution, car l' get()appel exécutera la requête et retournera les résultats de la base de données, puis les count()exécute sur la collection.
Trevor Gehman

1
$solution = $query->distinct()
            ->groupBy
            (
                [
                    'array',
                    'of',
                    'columns',
                ]
            )
            ->addSelect(
                [
                    'columns',
                    'from',
                    'the',
                    'groupby',
                ]
            )
            ->get();

N'oubliez pas que le groupe par est facultatif, cela devrait fonctionner dans la plupart des cas lorsque vous souhaitez qu'un groupe de comptage par exclure les valeurs de sélection en double, addSelect est une méthode d'instance de querybuilder.


0

Distinct ne prend pas d'arguments car il ajoute DISTINCT dans votre requête SQL, cependant, vous pouvez avoir besoin de définir le nom de colonne avec lequel vous souhaitez sélectionner distinct. Ainsi, si vous avez Flight->select('project_id')->distinct()->get()est équivalent à SELECT DISTINCT 'project_id' FROM flightset vous pouvez maintenant ajouter d'autres modificateurs comme count () ou même des requêtes éloquentes brutes.


0

Sur la base de la documentation Laravel pour les requêtes brutes, j'ai pu obtenir le décompte d'un champ de sélection pour travailler avec ce code dans le modèle de produit.

public function scopeShowProductCount($query)
{
    $query->select(DB::raw('DISTINCT pid, COUNT(*) AS count_pid'))
          ->groupBy('pid')
          ->orderBy('count_pid', 'desc');
}

Cette façade a fonctionné pour obtenir le même résultat dans le contrôleur:

$products = DB::table('products')->select(DB::raw('DISTINCT pid, COUNT(*) AS count_pid'))->groupBy('pid')->orderBy('count_pid', 'desc')->get();

Le vidage résultant pour les deux requêtes était le suivant:

#attributes: array:2 [
  "pid" => "1271"
  "count_pid" => 19
],
#attributes: array:2 [
  "pid" => "1273"
  "count_pid" => 12
],
#attributes: array:2 [
  "pid" => "1275"
  "count_pid" => 7
]

-1

Cela fonctionnait pour moi alors essayez ceci: $ ad-> getcodes () -> distinct ('pid') -> count ()


Salut bienvenue à SO. Lorsque vous répondez à une question, veuillez fournir des informations supplémentaires sur le code que vous fournissez. Des contributions comme celle-ci sont les bienvenues, mais d'autres à l'avenir pourraient bénéficier d'une explication de tir
Deepend

-3

essaye ça

$ad->getcodes()->groupby('pid')->distinct()->count('pid')
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.