J'ai besoin de récupérer toutes les lignes d'une table où 2 colonnes combinées sont toutes différentes. Je veux donc toutes les ventes qui n'ont pas d'autres ventes qui ont eu lieu le même jour pour le même prix. Les ventes qui sont uniques en fonction du jour et du prix seront mises à jour à un statut actif.
Je pense donc:
UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
FROM sales
HAVING count = 1)
Mais mon cerveau me fait mal d'aller plus loin que ça.
Si vous réunissez les réponses jusqu'à présent, nettoyez et améliorez, vous arriverez à cette requête supérieure:
Ce qui est beaucoup plus rapide que l'un ou l'autre. Détruit les performances de la réponse actuellement acceptée par le facteur 10 - 15 (dans mes tests sur PostgreSQL 8.4 et 9.1).
Mais c'est encore loin d'être optimal. Utilisez une
NOT EXISTS
(anti) semi-jointure pour des performances encore meilleures.EXISTS
est du SQL standard, existe depuis toujours (au moins depuis PostgreSQL 7.2, bien avant que cette question ne soit posée) et correspond parfaitement aux exigences présentées:db <> violon ici
Old SQL Fiddle
Clé unique pour identifier la ligne
Si vous n'avez pas de clé primaire ou unique pour la table (
id
dans l'exemple), vous pouvez remplacer par la colonne systèmectid
aux fins de cette requête (mais pas à d'autres fins):Chaque table doit avoir une clé primaire. Ajoutez-en un si vous n'en avez pas encore. Je suggère une
serial
ou uneIDENTITY
colonne dans Postgres 10+.En relation:
Comment est-ce plus rapide?
La sous-requête dans l'
EXISTS
anti-semi-jointure peut cesser d'être évaluée dès que la première dupe est trouvée (inutile de chercher plus loin). Pour une table de base avec peu de doublons, cela n'est que légèrement plus efficace. Avec beaucoup de doublons, cela devient beaucoup plus efficace.Exclure les mises à jour vides
Pour les lignes qui ont déjà
status = 'ACTIVE'
cette mise à jour, cela ne changera rien, mais insérez toujours une nouvelle version de ligne à plein coût (des exceptions mineures s'appliquent). Normalement, vous ne le souhaitez pas. Ajoutez une autreWHERE
condition comme illustré ci-dessus pour éviter cela et le rendre encore plus rapide:Si
status
est définiNOT NULL
, vous pouvez simplifier pour:Le type de données de la colonne doit prendre en charge l'
<>
opérateur. Certains types aimentjson
pas. Voir:Différence subtile dans la gestion NULL
Cette requête (contrairement à la réponse actuellement acceptée par Joel ) ne traite pas les valeurs NULL comme égales. Les deux lignes suivantes pour
(saleprice, saledate)
seraient qualifiées de "distinctes" (bien qu'elles semblent identiques à l'œil humain):Passe également dans un index unique et presque partout ailleurs, car les valeurs NULL ne sont pas comparables égales selon la norme SQL. Voir:
OTOH,
GROUP BY
,DISTINCT
ouDISTINCT ON ()
traiter les valeurs NULL comme égales. Utilisez un style de requête approprié en fonction de ce que vous souhaitez réaliser. Vous pouvez toujours utiliser cette requête plus rapide avecIS NOT DISTINCT FROM
au lieu de=
pour une ou toutes les comparaisons pour que la comparaison NULL soit égale. Plus:Si toutes les colonnes comparées sont définies
NOT NULL
, il n'y a pas de place pour le désaccord.la source
count(*)
est plus efficace quecount(<expression>)
. Essayez-le. Postgres a une implémentation plus rapide pour cette variante de la fonction d'agrégation. Peut-être confondez-vous Postgres avec un autre SGBDR?Le problème avec votre requête est que lorsque vous utilisez une clause GROUP BY (ce que vous faites essentiellement en utilisant distinct), vous ne pouvez utiliser que des colonnes que vous regroupez ou agrégez des fonctions. Vous ne pouvez pas utiliser l'ID de colonne car il existe des valeurs potentiellement différentes. Dans votre cas, il n'y a toujours qu'une seule valeur en raison de la clause HAVING, mais la plupart des SGBDR ne sont pas assez intelligents pour le reconnaître.
Cela devrait cependant fonctionner (et n'a pas besoin d'une jointure):
Vous pouvez également utiliser MAX ou AVG au lieu de MIN, il est uniquement important d'utiliser une fonction qui renvoie la valeur de la colonne s'il n'y a qu'une seule ligne correspondante.
la source
Je veux sélectionner les valeurs distinctes d'une colonne «GrondOfLucht» mais elles doivent être triées dans l'ordre indiqué dans la colonne «tri». Je ne peux pas obtenir les valeurs distinctes d'une seule colonne en utilisant
Il donnera également la colonne «tri» et parce que «GrondOfLucht» ET «tri» n'est pas unique, le résultat sera TOUTES les lignes.
utiliser le GROUPE pour sélectionner les enregistrements de 'GrondOfLucht' dans l'ordre donné par 'tri
la source
Si votre SGBD ne prend pas en charge distinct avec plusieurs colonnes comme ceci:
La sélection multiple en général peut être exécutée en toute sécurité comme suit:
Comme cela peut fonctionner sur la plupart des SGBD et que cela devrait être plus rapide que le regroupement par solution, vous évitez la fonctionnalité de regroupement.
la source