2010-09-14 11 views
0

d'abord tout ce que je suis en utilisant Oracle 10g expressSélectionnez trois lignes, deux d'entre eux (groupés) unique autre filtré par une autre colonne (SQL)

Donc, il y a trois colonnes que je veux choisir:

[nom_domaine] [index_path] [nom_collection]

maintenant il y a deux colonnes que je veux être unique (en tant que groupe):

[nom_domaine] [index_path]

Ensuite, je veux sélectionner la rangée sur laquelle une autre colonne [gen_timestamp] est la plus récente.

Donc, ma question est de savoir comment puis-je essentiellement:

SELECT domain_name, index_path, MIN(collection_name) collection_name 
FROM TABLENAMEHERE 
GROUP BY domain_name, index_path; 

mais au lieu de sélectionner le min nom_collection, sélectionnez la ligne ont été [gen_timestamp] est le plus récent.


Pour clarifier quelques questions que je pouvais voir des gens demander:

Avez-vous besoin d'une valeur unique de nom_domaine, et une valeur unique de index_path, ou une combinaison unique des deux?

COMBINAISON unique des deux.

Donc il y a plusieurs lignes du même [domain_name] [index_path]?

Oui.


Voici le code que je travaille avec maintenant, mais il ne fonctionne pas tout à fait:

select domain_name, index_path, collection_name 
    from my_table outr 
     inner join 
     (select domain_name, index_path, collection_name, 
       max(gen_timestamp) 
        over (partition by domain_name, index_path) gen_timestamp 
      from my_table) innr 
where outr.domain_name = innr.domain_name 
    and outr.index_path = innr.index_path 
    and outr.collection_name = innr.collection_name 
    and outr.gen_timestamp = innr.gen_timestamp 

Répondre

1

Il existe une fonction d'agrégat disponible depuis la version 9 qui fait exactement ce que vous demandez. Malheureusement, je n'ai pas encore vu celui-ci mentionné dans les réponses dans vos deux fils.

Une table pour démontrer votre problème:

SQL> create table tablenamehere (domain_name,index_path,collection_name,gen_timestamp) 
    2 as 
    3 select 'A', 'Z', 'a collection name', systimestamp from dual union all 
    4 select 'A', 'Z', 'b collection name', systimestamp - 1 from dual union all 
    5 select 'A', 'Y', 'c collection name', systimestamp from dual union all 
    6 select 'B', 'X', 'd collection name', systimestamp - 2 from dual union all 
    7 select 'B', 'X', 'e collection name', systimestamp - 4 from dual union all 
    8 select 'B', 'X', 'f collection name', systimestamp from dual 
    9/

Table created. 

Et votre requête qui montre min (nom_collection). Cette montre « d nom de la collection », mais vous voulez pour montrer « nom de la collection f »:

SQL> SELECT domain_name, index_path, MIN(collection_name) collection_name 
    2 FROM TABLENAMEHERE 
    3 GROUP BY domain_name, index_path 
    4/

D I COLLECTION_NAME 
- - ----------------- 
A Y c collection name 
A Z a collection name 
B X d collection name 

3 rows selected. 

Pas besoin d'appliquer des fonctions analytiques à toutes vos lignes et filtre sur ces résultats: vous faites une agrégation et la fonction LAST fait votre travail exactement.Voici un lien vers la documentation: http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions071.htm#sthref1495

SQL> select domain_name 
    2  , index_path 
    3  , max(collection_name) keep (dense_rank last order by gen_timestamp) collection_name 
    4 from tablenamehere 
    5 group by domain_name 
    6  , index_path 
    7/

D I COLLECTION_NAME 
- - ----------------- 
A Y c collection name 
A Z a collection name 
B X f collection name 

3 rows selected. 

Cordialement, Rob .

2

Cela risque de doublons en cas de valeurs en double gen_timestamp:

SELECT x.domain_name, 
     x.index_path, 
     x.collection_name 
    FROM TABLENAMEHERE x 
    JOIN (SELECT t.domain_name, 
       t.index_path, 
       MAX(t.gen_timestamp) AS max_ts 
      FROM YOUR_TABLE t 
     GROUP BY t.domain_name, t.index_path) y ON y.domain_name = x.domain_name 
               AND y.index_path = x.index_path 
               AND y.max_ts = x.gen_timestamp 
ORDER BY domain_name, index_path 

En utilisant ROW_NUMBER (9i +), aucun risque de doublons:

WITH summary AS (
    SELECT t.domain_name, 
     t.index_path, 
     t.collection_name, 
     ROW_NUMBER() OVER(PARTITION BY t.domain_name, 
             t.index_path 
           ORDER BY t.gen_timestamp DESC) AS rank 
    FROM YOUR_TABLE t) 
    SELECT s.domain_name, 
     s.index_path, 
     s.collection_name 
    FROM summary s 
    WHERE s.rank = 1 
ORDER BY domain_name, index_path 
+0

qui sélectionne l'horodatage réel alors que je souhaite sélectionner le nom de collection auquel l'horodatage fait référence. Quelque chose comme ce que je viens d'éditer à la question. –

+0

@jacobnlsn: Vous voulez donc que la valeur 'collection_name' soit associée au plus haut' gen_timestamp' par paire domaine/chemin - correct? –

+0

Je veux les valeurs collection_name, domain_name et index_path associées à la paire gen_timestamp la plus élevée par paire domaine/chemin. Donc tu étais très proche. –

0
select distinct domain_name, 
       index_path, 
       first(collection_name) over (partition by domain_name, index_path order by gen_timestamp desc) 
from Your_Table 
+0

Vous êtes sûr que vous avez besoin de PARTITION BY dans l'analyse, ou ce sera juste le premier nom de collection avec la valeur d'horodatage la plus élevée ... –

+0

@OMG Poneys: Vous avez raison, bien sûr. – Allan