Si vous réunissez les réponses jusqu'à présent, nettoyez et améliorez, vous arriverez à cette requête supérieure:
UPDATE sales
SET    status = 'ACTIVE'
WHERE  (saleprice, saledate) IN (
    SELECT saleprice, saledate
    FROM   sales
    GROUP  BY saleprice, saledate
    HAVING count(*) = 1 
    );
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. EXISTSest 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:
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
 Old SQL Fiddle
Clé unique pour identifier la ligne
Si vous n'avez pas de clé primaire ou unique pour la table ( iddans l'exemple), vous pouvez remplacer par la colonne système ctidaux fins de cette requête (mais pas à d'autres fins):
   AND    s1.ctid <> s.ctid
Chaque table doit avoir une clé primaire. Ajoutez-en un si vous n'en avez pas encore. Je suggère une serialou une IDENTITYcolonne dans Postgres 10+.
En relation:
Comment est-ce plus rapide?
La sous-requête dans l' EXISTSanti-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 autre WHEREcondition comme illustré ci-dessus pour éviter cela et le rendre encore plus rapide:
Si statusest défini NOT NULL, vous pouvez simplifier pour:
AND status <> 'ACTIVE';
Le type de données de la colonne doit prendre en charge l' <>opérateur. Certains types aiment jsonpas. 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):
(123, NULL)
(123, NULL)
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, DISTINCTou DISTINCT 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 avec IS NOT DISTINCT FROMau 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.