2009-06-09 5 views
3

Voici un exemple de données que j'ai.Regroupement avancé sans utiliser de sous-requête

-ID-  -Rank-  -Type-  -Status- -Amount- 
1142474  2  Under Offer Approved 23 
1148492  1  Present  Current  56 
1148492  2  Under Offer Approved 3 
2273605  1  Present  Current  24 

Lorsque l'ID est le même, je veux seulement l'enregistrement avec le rang le plus élevé. Donc, le résultat final de la requête.

-ID-  -Rank-  -Type-  -Status- -Amount- 
1142474  2  Under Offer Approved 23 
1148492  1  Present  Current  56 
2273605  1  Present  Current  24 

Maintenant, pour obtenir l'ensemble de données d'origine est une opération coûteuse, donc je ne pas veulent faire un groupe par l'ID puis minutes rang et rejoint ensuite en arrière sur l'ensemble de données à nouveau. Par conséquent, la requête doit faire son travail d'une autre manière.

Vive Anthony

Répondre

1
select t1.id 
     , t1.rank 
     , t1.type 
     , t1.status 
     , t1.amount 

from my_table t1 

     left outer join my_table as t2 
     on t1.id = t2.id 
    and 
     t2.rank < t1.rank 

where t2.id is null 
+0

Dans ce cas, que se trouve t2? –

+0

@Anthony: la jointure à t2 est aussi appelée auto-jointure. C'est une autre copie de la même table. La raison pour laquelle cela fonctionne est que nous spécifions dans le prédicat (les conditions de jointure et la clause WHERE) que nous voulons exclure tout sauf l'élément le mieux classé pour chaque identifiant. – bernie

+0

@adam: Le problème est que pour extraire les données de my_table est très cher (ie entre 2 et 6 secondes) donc je voudrais éviter de rejoindre à nouveau la table ... –

0

Les options disponibles incluent en général:

  • Stocker les données illustrées dans une table temporaire, puis interroger la table temp.
  • Utilisez une clause WITH pour définir la requête complexe, puis demandez au SGBD de trier la requête.

La clause WITH permet effectivement de donner un nom à une sous-requête; l'optimiseur évitera de le réévaluer si possible. La solution de table TEMP est susceptible d'être la plus simple. Et cela fera GROUP BY d'ID et MIN (rang) et rejoignent.

2
SELECT * FROM TheTable 
WHERE 1 = ROW_NUMBER() OVER (PARTITION BY ID ORDER BY Rank DESC) 
+0

C'était mon premier instinct. Peut-être que le PO affichera des résultats de synchronisation. – bernie

+0

Juste pour l'enregistrement, dans ma situation ce cas une erreur - "Les fonctions fenêtrées peuvent seulement apparaître dans les clauses SELECT ou ORDER BY." J'ai donc dû mettre la partie supérieure dans une sous-requête et la partie où dans la requête externe. –

6

Cela fonctionne:

with temp as (
select *, row_number() over (partition by id order by rank) as rownum 
from table_name 
) 
select * from temp where rownum = 1 

donnera un enregistrement par id où rang représente le moins

0

Pourquoi obtient le jeu de données si cher, je ne vois rien terriblement complexe ici. Avez-vous les index dont vous avez besoin, la requête les utilise-t-elle? Les statistiques sont-elles périmées?

+0

Pour les besoins de la question, j'ai simplifié le scénario. Fondamentalement, la table est une fonction Table_valued dont les unions proviennent de 2 autres fonctions Table_valued, chacune utilisant environ 6 tables temporaires pour construire les résultats. Cela est dû au niveau de normalisation qui est présent dans la base de données et à la quantité de données à obtenir pour construire une image des données. Vraiment, ces données doivent être capturées dans une vue Materialize ou quelque chose de similaire. Mais je ne peux pas faire de changement comme celui-ci dans ce cycle de publication. à votre santé –