Comment puis-je (ou puis-je) SELECT DISTINCT sur plusieurs colonnes?
-
09-06-2019 - |
Question
J'ai besoin de récupérer toutes les lignes d'une table où les 2 colonnes sont toutes différentes.Donc, je veux que toutes les ventes qui n'ont pas d'autres ventes qui s'est passé le même jour pour le même prix.Les ventes qui sont uniques en fonction du jour et le prix sera mis à jour à un état actif.
Donc, je suis en train de penser:
UPDATE sales
SET status = 'ACTIVE'
WHERE id IN (SELECT DISTINCT (saleprice, saledate), id, count(id)
FROM sales
HAVING count = 1)
Mais mon cerveau fait mal d'aller encore plus loin.
La solution
SELECT DISTINCT a,b,c FROM t
est environ l'équivalent de:
SELECT a,b,c FROM t GROUP BY a,b,c
C'est une bonne idée d'obtenir utilisé pour le GROUPE PAR la syntaxe, car il est plus puissant.
Pour votre requête, je ferais comme ceci:
UPDATE sales
SET status='ACTIVE'
WHERE id IN
(
SELECT id
FROM sales S
INNER JOIN
(
SELECT saleprice, saledate
FROM sales
GROUP BY saleprice, saledate
HAVING COUNT(*) = 1
) T
ON S.saleprice=T.saleprice AND s.saledate=T.saledate
)
Autres conseils
Si vous mettez ensemble les réponses jusqu'à présent, les nettoyer et de les améliorer, vous arrivez à ce supérieur de la requête:
UPDATE sales
SET status = 'ACTIVE'
WHERE (saleprice, saledate) IN (
SELECT saleprice, saledate
FROM sales
GROUP BY saleprice, saledate
HAVING count(*) = 1
);
Qui est beaucoup plus rapide que l'un d'eux.Les armes nucléaires de la performance de la actuellement accepté de répondre par un facteur de 10 - 15 (dans mes tests sur PostgreSQL 8.4 9.1).
Mais cela est encore loin d'être optimale.L'utilisation d'un NOT EXISTS
(anti-)semi-jointure pour des performances encore meilleures. EXISTS
est SQL standard, a été autour pour toujours (au moins depuis PostgreSQL 7.2, longtemps avant que cette question a été posée) et l'adapte les exigences parfaitement:
UPDATE sales s
SET status = 'ACTIVE'
WHERE NOT EXISTS (
SELECT FROM sales s1 -- SELECT list can be empty for EXISTS
WHERE s.saleprice = s1.saleprice
AND s.saledate = s1.saledate
AND s.id <> s1.id -- except for row itself
)
AND s.status IS DISTINCT FROM 'ACTIVE'; -- avoid empty updates. see below
db<>violon ici
Ancien SQL Violon
Clé Unique pour identifier la ligne
Si vous n'avez pas une clé primaire ou unique pour la table (id
dans l'exemple), vous pouvez le remplacer par le système de colonne ctid
aux fins de la présente requête (mais pas pour d'autres fins):
AND s1.ctid <> s.ctid
Chaque table doit avoir une clé primaire.Ajoutez-en un si vous n'avez pas, encore.Je vous propose un serial
ou un IDENTITY
colonne dans Postgres 10+.
Connexes:
Comment est-ce plus rapide?
La sous-requête dans la EXISTS
anti-semi-jointure peut arrêter l'évaluation dès la première dupe est trouvé (pas de point en regardant de plus).Pour une table de base avec quelques doublons, ce n'est que légèrement plus efficace.Avec beaucoup de doublons cela devient façon plus efficace.
Exclure vide mises à jour
Pour les lignes qui ont déjà status = 'ACTIVE'
cette mise à jour ne change rien, mais encore l'insertion d'une nouvelle version de ligne à coût complet (quelques exceptions s'appliquent).Normalement, vous ne voulez pas cela.Ajouter un autre WHERE
condition comme démontré ci-dessus pour éviter cela et le rendre encore plus rapide:
Si status
est défini NOT NULL
, vous pouvez simplifier à:
AND status <> 'ACTIVE';
Différence subtile dans la gestion des valeurs NULL
Cette requête (contrairement à la actuellement accepté de répondre par Joel) ne permet pas de traiter les valeurs NULLES comme des égaux.Les deux lignes suivantes pour (saleprice, saledate)
sont admissibles à titre de "distinct" (bien qu'une apparence identique à l'œil humain):
(123, NULL)
(123, NULL)
Passe aussi dans un index unique et presque partout ailleurs, puisque les valeurs NULL ne comparez pas égaux selon le standard SQL.Voir:
Otoh, que, GROUP BY
, DISTINCT
ou DISTINCT ON ()
traiter les valeurs NULLES comme des égaux.Utiliser une requête de style en fonction de ce que vous voulez atteindre.Vous pouvez toujours utiliser cette requête plus rapide avec IS NOT DISTINCT FROM
au lieu de =
pour toutes les comparaisons de rendre NUL comparer l'égalité.Plus:
Si toutes les colonnes sont définis par rapport NOT NULL
, il n'y a pas de place pour le désaccord.
Le problème avec votre requête, c'est que lors de l'utilisation d'une clause GROUP BY (qui vous font essentiellement en utilisant différentes), vous pouvez uniquement utiliser les colonnes que vous groupe ou par des fonctions d'agrégation.Vous ne pouvez pas utiliser l'id de colonne, car il y a potentiellement des valeurs 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 intelligent pour reconnaître que.
Cela devrait fonctionner, en revanche (et n'a pas besoin d'une jointure):
UPDATE sales
SET status='ACTIVE'
WHERE id IN (
SELECT MIN(id) FROM sales
GROUP BY saleprice, saledate
HAVING COUNT(id) = 1
)
Vous pouvez également utiliser MAX AVG ou au lieu de MIN, il est seulement important d'utiliser une fonction qui retourne la valeur de la colonne si il y a une seule ligne correspondante.
Je veux sélectionner les valeurs distinctes d'une colonne 'GrondOfLucht", mais ils doivent être triés dans l'ordre, dans la colonne "sortering'.Je ne peux pas obtenir les valeurs distinctes d'une seule colonne à l'aide de
Select distinct GrondOfLucht,sortering
from CorWijzeVanAanleg
order by sortering
Il sera également donner à la colonne "sortering" et parce que "GrondOfLucht" ET "sortering" n'est pas unique, le résultat sera de TOUTES les lignes.
utiliser le GROUPE pour sélectionner les enregistrements de "GrondOfLucht" dans l'ordre donné par 'sortering
SELECT GrondOfLucht
FROM dbo.CorWijzeVanAanleg
GROUP BY GrondOfLucht, sortering
ORDER BY MIN(sortering)
Si votre SGBD ne supporte pas distinctes avec plusieurs colonnes comme ceci:
select distinct(col1, col2) from table
Multi sélection, en général, peut être exécuté en toute sécurité comme suit:
select distinct * from (select col1, col2 from table ) as x
Comme cela peut fonctionner sur la plupart des SGBD, et cela devrait être plus rapide que groupe par la solution que vous êtes en évitant les fonctionnalités de regroupement.