2010-07-09 63 views
1

我正在尝试使Teradata SQL查询返回每个用户的按时间顺序访问日期 n。例如,Teradata结果中的第n项结果

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 

我想是这样的下方,但Teradata的尖叫着说,“有序分析功能在WHERE条款允许的。”我拉了一段时间的头发,但没有取得多大进展。任何人看到这个?

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

from visitstable 
    where rnum = 2 

如果我排除where那么我的结果看起来很有希望...我只是不能提取我所需要的!

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 

在此先感谢您的帮助!

回答

1
SELECT 
    user 

FROM 
    visitstable 

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

我从您的评论中看到,您不一定要依靠Teradata特定的QUALIFY。以下是一种便携式解决方案(许多RDBMS现在支持CTE):

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

谢谢,亚当。 TD不喜欢第一种解决方案。 “QUALIFY BY ROW_NUMBER()”中的“BY”必须去。 第二个让我的大脑发出嘶嘶声,这在星期五的早晨很棒。谢谢! – Chris 2010-07-09 15:33:42

+0

糟糕,关于'BY'错字。我现在编辑了,谢谢。第二个示例是一个可用于主查询的临时表。一旦我结束语法,我注意到通过简单地将现有查询的第一步移动到'WITH'子句中,可以获得巨大的性能提升。祝你好运。 – bernie 2010-07-09 15:44:23

0

您使用的是什么版本的SQL?它看起来像MS SQL Server的后继版本,所以请尝试使用“公用表表达式”像这样...

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

的语法可能需要一个小的调整,但是这是一般原则。

+0

这是Teradata ...我会看看我是否可以翻译您的建议。谢谢。 – Chris 2010-07-09 15:08:15

+1

如果你没有where子句,你的查询是否工作,并返回预期的行号?如果是这样,您可以将结果插入临时表中,然后从中选择适当的行号。 – 2010-07-09 15:17:20

+0

是的,临时表可能可移植工作...我只是想尽量减少临时表的数量,因为有数以百万计的记录。 – Chris 2010-07-09 15:24:57

1

哦,天堂禁止我应该看看文档。仅供参考,看起来像qualify可让您指定有序的分析约束。然而,qualify没有ANSI,所以我仍然端出点便携式解决方案...

我可以这样做:

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

from visitstable 
qualify rnum=2 

...并获得...

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

将它书签! :)

+0

+1找到你自己的解决方案。 – bernie 2010-07-09 15:51:05