使用间隔对记录进行分组的Teradata sql查询

使用间隔对记录进行分组的Teradata sql查询,sql,teradata,Sql,Teradata,在Teradata SQL中,如何在8秒的时间间隔内为创建的记录组分配相同的行号 例如:- Customerid Customername Itembought dateandtime (yyy-mm-dd hh:mm:ss) 100 ALex Basketball 2017-02-10 10:10:01 100 ALex Circketb

在Teradata SQL中,如何在8秒的时间间隔内为创建的记录组分配相同的行号

例如:-

Customerid Customername   Itembought   dateandtime
                                       (yyy-mm-dd hh:mm:ss)
100           ALex        Basketball   2017-02-10 10:10:01
100           ALex        Circketball  2017-02-10 10:10:06
100           ALex        Baseball     2017-02-10 10:10:08
100           ALex        volleyball   2017-02-10 10:11:01
100          ALex         footbball    2017-02-10 10:11:05
100          ALex         ringball     2017-02-10 10:11:08
100         Alex          football     2017-02-10 10:12:10
我的预期结果应该有一个额外的列,带有行\号,它应该为客户在8秒内的所有购买分配相同的编号:参考下面的预期结果

Customerid Customername Itembought dateandtime            Row_number
                                   (yyy-mm-dd hh:mm:ss) 
100           ALex      Basketball 2017-02-10 10:10:01      1
100           ALex      Circketball 2017-02-10 10:10:06     1
100           ALex      Baseball    2017-02-10 10:10:08     1
100          ALex       volleyball  2017-02-10 10:11:01     2
100          ALex       footbball   2017-02-10 10:11:05     2
100          ALex       ringball    2017-02-10 10:11:08     2
100         Alex        football    2017-02-10 10:12:10     3

这是使用递归cte实现的一种方法。当上一行的时间戳大于8时,将其运行总差值重置为0,并启动一个新组

WITH ROWNUMS AS
  (SELECT T.*
         ,ROW_NUMBER() OVER(PARTITION BY ID ORDER BY TM) AS RNUM 
         /*Replace DATEDIFF with Teradata specific function*/
         ,DATEDIFF(SECOND,COALESCE(MIN(TM) OVER(PARTITION BY ID
                                                ORDER BY TM ROWS BETWEEN 1 PRECEDING AND CURRENT ROW), TM),TM) AS DIFF
   FROM T --replace this with your tablename and add columns as required
   )
,RECURSIVE CTE(ID,TM,DIFF,SUM_DIFF,RNUM,GRP) AS
  (SELECT ID,
          TM,
          DIFF,
          DIFF,
          RNUM,
          CAST(1 AS int)
   FROM ROWNUMS
   WHERE RNUM=1
     UNION ALL
   SELECT T.ID,
          T.TM,
          T.DIFF,
          CASE WHEN C.SUM_DIFF+T.DIFF > 8 THEN 0 ELSE C.SUM_DIFF+T.DIFF END,
          T.RNUM,
          CAST(CASE WHEN C.SUM_DIFF+T.DIFF > 8 THEN T.RNUM ELSE C.GRP END AS int)
   FROM CTE C
   JOIN ROWNUMS T ON T.RNUM=C.RNUM+1 AND T.ID=C.ID
   )
SELECT ID,
       TM,
       DENSE_RANK() OVER(PARTITION BY ID ORDER BY GRP) AS row_num
FROM CTE

使用Teradata的周期数据类型和可怕的:

考虑表test32:

 SELECT * FROM test32

+----+----+------------------------+
| f1 | f2 |           f3           |
+----+----+------------------------+
|  1 |  2 | 2017-05-11 03:59:00 PM |
|  1 |  3 | 2017-05-11 03:59:01 PM |
|  1 |  4 | 2017-05-11 03:58:58 PM |
|  1 |  5 | 2017-05-11 03:59:26 PM |
|  1 |  2 | 2017-05-11 03:59:28 PM |
|  1 |  2 | 2017-05-11 03:59:46 PM |
+----+----+------------------------+
以下内容将对您的记录进行分组:

WITH 
normalizedCTE AS
    (
        SELECT *
        FROM TABLE
            (
                td_normalize_overlap_meet(NEW VARIANT_TYPE(periodCTE.f1), periodCTE.fper)
                RETURNS (f1 integer, fper PERIOD(TIMESTAMP(0)), recordCount integer)
                HASH BY f1
                LOCAL ORDER BY f1, fper
            ) as output(f1, fper, recordcount)
    ),
periodCTE AS 
    (
        SELECT f1, f2, f3, PERIOD(f3, f3 + INTERVAL '9' SECOND) as fper FROM test32
    )


SELECT t2.f1, t2.f2, t2.f3, t1.fper, DENSE_RANK() OVER (PARTITION BY t2.f1 ORDER BY t1.fper) as fgroup
FROM normalizedCTE t1
    INNER JOIN periodCTE t2 ON
        t1.fper P_INTERSECT t2.fper IS NOT NULL
结果:

+----+----+------------------------+-------------+
| f1 | f2 |           f3           | fgroup      |
+----+----+------------------------+-------------+
|  1 |  2 | 2017-05-11 03:59:00 PM |           1 |
|  1 |  3 | 2017-05-11 03:59:01 PM |           1 |
|  1 |  4 | 2017-05-11 03:58:58 PM |           1 |
|  1 |  5 | 2017-05-11 03:59:26 PM |           2 |
|  1 |  2 | 2017-05-11 03:59:28 PM |           2 |
|  1 |  2 | 2017-05-11 03:59:46 PM |           3 |
+----+----+------------------------+-------------+
Teradata中的
Period
是一种保存日期或日期时间范围的特殊数据类型。第一个参数是范围的开始,第二个参数是结束时间(最多,但不包括),这就是为什么它是“+9秒”)。结果是我们得到了一个8秒的“周期”,其中每个记录可能与另一个记录“相交”

然后,我们使用
td\u normalize\u overlap\u meet
合并相交的记录,共享
f1
字段的值作为键。在您的情况下,这将是
customerid
。这一客户的结果是三条记录,因为我们有三个组“重叠”或“满足”彼此的时间段

然后,我们将td_normalize_overlap_meet输出与确定周期时的输出连接起来。我们使用
P_INTERSECT
函数查看标准化CTE中的哪些周期与初始周期CTE中的周期相交。从该
P_INTERSECT
join的结果中,我们从每个CTE获取所需的值


最后,
densite\u Rank()
根据每组的标准化周期为我们提供了一个等级。

我将以与vkp不同的方式解释这个问题。另一行8秒内的任何一行都应在同一组中。这些值可以链接在一起,因此整个跨度可以超过8秒

这种方法的优点是不需要递归CTE,因此应该更快。(当然,如果OP与定义不一致,这不是优势。)

基本思想是查看以前的日期/时间值;如果相距超过8秒,则添加一个标志。标志的累计和是您要查找的行号

  select t.*,
         sum(case when prev_dt >= dateandtime - interval '8' second
                  then 0 else 1
             end) over (partition by customerid order by dateandtime
                       ) as row_number
  from (select t.*,
               max(dateandtime) over (partition by customerid order by dateandtime row between 1 preceding and 1 preceding) as prev_dt
        from t
       ) t;

如果有一行是
10:10:15
,那么这是第一组的一部分还是一个新组呢?我想它应该是一个新组@dnoeth。。根据说明..每个用户8秒内的所有行必须从第一个时间戳开始位于一个组中。为什么要回滚ObsidManager的编辑?但是
10:10:15
10:10:08
之后的8秒内。是的,它应该是新组,基本上,我希望为在8秒内购买多件商品的客户分配相同的行号。抱歉。我无意中回滚了ObsidManager的编辑。我不知道是否有其他方法可以实现此目的。特别是当达到8秒间隔时组必须重设时。@vkp。他们为什么不解决这个问题呢?这里有“lag”,只是拼写不同而已。@GordonLinoff听到了吗!听到了!Teradata中最好有
lag()
lead()
<代码>最大值()超过(…行之间…)很麻烦,一点也不直观。滞后和超前是ansi标准的一部分吗?我认为…之间的
行是,但
滞后
领先
不是,但我可能完全疯了。@Andrew。是的,它们是标准的窗口功能。考虑到Teradata支持这一功能,令人惊讶的是他们不只是把功能放进去。这里有三个非常不同的答案,都解决了这个非常困难的问题。挑一个,带着它跑。对于像这样的间隔和孤岛间隔问题,没有简单的答案。@JNevill:如果你想在8秒内完成拍摄,你应该使用
句点(f3,f3+间隔'9'秒)
,目前你只拍摄了16秒:-)@Dnoeth,我拍摄了+/-8秒,但只要+8也可能有效。反正都正常化了,所以我认为这是一次洗牌。我想我的网撒得太宽了。你会把10:10:00和10:10:15结合起来,在+/-8秒的时候。