Je veux exécuter cette requête:
SELECT DISTINCT ON (address_id) purchases.address_id, purchases.*
FROM purchases
WHERE purchases.product_id = 1
ORDER BY purchases.purchased_at DESC
Mais je reçois cette erreur:
PG :: Erreur: ERREUR: les expressions SELECT DISTINCT ON doivent correspondre aux expressions ORDER BY initiales
L'ajout en address_id
tant que première ORDER BY
expression fait taire l'erreur, mais je ne veux vraiment pas ajouter de tri address_id
. Est-il possible de faire sans passer commande par address_id
?
Réponses:
La documentation dit:
Documentation officielle
Vous devrez donc ajouter le
address_id
à la commande avant le.Alternativement, si vous recherchez la ligne complète qui contient le produit acheté le plus récent pour chacun
address_id
et ce résultat trié parpurchased_at
alors vous essayez de résoudre un plus grand problème N par groupe qui peut être résolu par les approches suivantes:La solution générale qui devrait fonctionner dans la plupart des SGBD:
Une solution plus orientée PostgreSQL basée sur la réponse de @ hkf:
Problème clarifié, étendu et résolu ici: sélection de lignes ordonnées par une colonne et distinctes d'une autre
la source
SELECT DISTINCT ON (purchases.purchased_at, address_id)
. Cependant, deux enregistrements avec le même adresse_id mais différentes valeurs de purchase_at entraîneront des doublons dans l'ensemble renvoyé. Assurez-vous que vous connaissez les données que vous interrogez.Vous pouvez trier par address_id dans une sous-requête, puis trier par ce que vous voulez dans une requête externe.
la source
select
, je ne pense pas que ce soit du code de production?address_id
deux fois (sans besoin). De nombreux clients ont des problèmes avec les noms de colonne en double.ORDER BY address_id DESC
est inutile et trompeur. Il ne fait rien d'utile dans cette requête. Le résultat est un choix arbitraire dans chaque ensemble de lignes avec le mêmeaddress_id
, pas la ligne avec le dernierpurchased_at
. La question ambiguë ne le demandait pas explicitement, mais c'est presque certainement l'intention du PO. En bref: n'utilisez pas cette requête . J'ai posté des alternatives avec explication.Une sous-requête peut le résoudre:
Les expressions principales dans
ORDER BY
doivent être d'accord avec les colonnes dansDISTINCT ON
, vous ne pouvez donc pas classer par différentes colonnes dans la mêmeSELECT
.N'utilisez un
ORDER BY
élément supplémentaire dans la sous-requête que si vous souhaitez sélectionner une ligne particulière dans chaque ensemble:Si c'est
purchased_at
possibleNULL
, réfléchissezDESC NULLS LAST
. Mais assurez-vous de faire correspondre votre index si vous avez l'intention de l'utiliser. Voir:Connexes, avec plus d'explications:
la source
DISTINCT ON
sans correspondanceORDER BY
. La première requête nécessite unORDER BY address_id
à l'intérieur de la sous-requête.DISTINCT ON
sansORDER BY
dans la même requête. Vous obtenez une ligne arbitraire de chaque ensemble de pairs défini par laDISTINCT ON
clause dans ce cas. Essayez-le ou suivez les liens ci-dessus pour plus de détails et des liens vers le manuel.ORDER BY
dans la même requête (la mêmeSELECT
) ne peut tout simplement pas être en désaccord avecDISTINCT ON
. Je l'ai expliqué aussi.ORDER BY
note «imprévisible sauf si utilisé» dans les documents, car cela n'a pas de sens pour moi que la fonctionnalité soit implémentée pour pouvoir traiter des ensembles de valeurs non consécutifs… mais ne vous permettra pas de exploiter cela avec un ordre explicite. Énervant.DISTINCT ON
(encore) trié par expressions.La fonction de fenêtre peut résoudre cela en un seul passage:
la source
address_id
. Le principe pourrait cependant fonctionner. Exemples connexes: stackoverflow.com/a/22064571/939860 ou stackoverflow.com/a/11533808/939860 . Mais il existe des requêtes plus courtes et / ou plus rapides pour le problème en question.Pour tous ceux qui utilisent Flask-SQLAlchemy, cela a fonctionné pour moi
la source
query.distinct(foo).from_self().order(bar)
Purchases.query
?Vous pouvez également le faire en utilisant la clause group by
la source
purchases
contient que les deux colonnesaddress_id
etpurchased_at
). À cause de celaGROUP BY
, vous devrez utiliser une fonction d'agrégation pour obtenir la valeur de chaque colonne non utilisée pour le regroupement, de sorte que ces valeurs proviendront toutes de différentes lignes du groupe, sauf si vous passez par une gymnastique laide et inefficace. Cela ne peut être résolu qu'en utilisant des fonctions de fenêtre plutôt queGROUP BY
.