2010-07-09 3 views
1

J'essaie de faire une requête SQL Teradata qui renverra la n -th date de visite chronologique pour chaque utilisateur. Par exemple,nième résultat dans le résultat Teradata

user | visit_date 
--------------------- 
    a  1/1  
    b  1/10 
    c  1/20 
    a  1/3 
    a  1/4 
    b  1/5 
    c  1/15 
    b  1/9 


> magic_query_for_Second_visit; 
user | second 
------------------ 
    a  1/3 
    b  1/9 
    c  1/20 

J'ai essayé quelque chose comme ci-dessous, mais Teradata hurlèrent que « les fonctions d'analyse commandés ne sont pas autorisés dans WHERE clause. » Je me suis tiré les cheveux pendant un moment mais je ne fais pas beaucoup de progrès. Quelqu'un a vu ça?

select user, 
    row_number() over (partition by user order by visit_date desc) as rnum 

from visitstable 
    where rnum = 2 

Si je le where alors exclure mon résultat semble prometteur ... Je ne peux pas extraire ce que je dois!

user | visit_date | rnum 
--------------------------- 
    a  1/1   1 
    a  1/3   2 
    a  1/4   3 
    b  1/5   1 
    b  1/9   2 
    b  1/10   3 
    c  1/15   1 
    c  1/20   2 

Merci d'avance pour l'aide!

Répondre

1
SELECT 
    user 

FROM 
    visitstable 

QUALIFY ROW_NUMBER() OVER (
    PARTITION BY 
     user 
    ORDER BY 
     visit_date DESC) = 2 

Je vois de votre commentaire que vous ne voulez pas nécessairement compter sur la QUALIFY Teradata spécifique. Ce qui suit est une sorte de solution-portable (autant de SGBDR soutiennent maintenant CTEs) en fonction de la réponse d'un autre chapitre:

WITH tmp (user, rnum) AS (
    SELECT 
     user, 
     ROW_NUMBER() OVER (
      PARTITION BY 
       user 
      ORDER BY 
       visit_date DESC) AS rnum 
    FROM 
     visitstable) 
SELECT 
    tmp.* 
FROM 
    tmp 
WHERE 
    tmp.rnum = 2 
+0

Merci, Adam. TD n'a pas aimé la première solution. Le "BY" dans 'QUALIFY BY ROW_NUMBER()' a dû partir. Le 2ème fait grésiller mon cerveau, ce qui est génial un vendredi matin. Merci! – Chris

+0

Oups, désolé pour la faute de frappe «BY». Je l'ai maintenant édité, merci. Le second exemple est une table temporaire mise à la disposition de votre requête principale. Une fois la syntaxe passée, j'ai remarqué d'énormes gains de performance en déplaçant simplement la première étape d'une requête existante vers la clause 'WITH'. Bonne chance à vous. – bernie

0

Quelle version de SQL utilisez-vous? Il ressemble à une version ultérieure de MS SQL Server, alors essayez d'utiliser une « expression de table commune » comme ça ...

with cte as ( select user, row_number() over (partition by user order by visit_date desc) as rnum from visitstable )

select * from cte where rnum = 2

La syntaxe peut nécessiter un peu de peaufinage, mais qui est le principe général.

+0

Il est Teradata ... Je vais voir si je peux traduire votre suggestion. Merci. – Chris

+1

Votre requête fonctionne-t-elle et renvoie-t-elle les numéros de ligne attendus, si vous n'avez pas la clause where? Si c'est le cas, vous pouvez insérer les résultats dans une table temporaire, puis sélectionner les numéros de ligne appropriés. –

+0

Oui, la table temporaire fonctionnerait probablement de manière portable ... Je voulais juste minimiser le nombre de tables temporaires, puisqu'il y a des centaines de millions d'enregistrements. – Chris

1

Oh, mon Dieu, je devrais regarder dans la documentation. Pour info, il semble que qualify vous permet de spécifier des contraintes analytiques ordonnées. Cependant, qualify n'est pas ANSI, donc je suis toujours distribuer des points pour une solution portable ...

je peux faire:

select user, 
    row_number() over (partition by user order by visit_date desc) as rnum 

from visitstable 
qualify rnum=2 

... et obtenir ...

user | visit_date | rnum 
----------------------------- 
    a  1/3   2 
    b  1/9   2 
    c  1/20   2 

Ajouter aux favoris! :)

+0

+1 pour trouver votre propre solution. – bernie

Questions connexes