Sql窗口函数得到累积列

时间:2017-04-19 08:08:50

标签: sql oracle

我有一张这样的表

+--------------------------------------------+
|id(autoincr)|session_id      |attmpt_counter|
+------------+----------------+--------------+
|0           |ses0            |0             |
|1           |ses0            |1             |
|2           |ses1            |0             |
|3           |ses1            |1             |
|4           |ses1            |1             |
|5           |ses1            |2             |
|6           |ses1            |3             |
|7           |ses2            |0             |
|8           |ses2            |0             |
|9           |ses2            |0             |
+------------+----------------+--------------+

对于窗口(按try_counter按session_id顺序分区)我希望通过以下数学进入:如果行'attempt_counter'的下一个值不大于先前值,则递增。 我想在没有函数的情况下得到一个累积此规则的表(尽可能使用row cross-rdbms sql)

+--------------------------------------------+---------------+
|id(autoincr)|session_id      |attmpt_counter|entrance       |
+------------+----------------+--------------+---------------+
|0           |ses0            |0             |0              |
|1           |ses0            |1             |0              |
|2           |ses1            |0             |0              |
|3           |ses1            |1             |0              |
|4           |ses1            |1             |1              |
|5           |ses1            |2             |1              |
|6           |ses1            |3             |1              |
|7           |ses2            |0             |0              |
|8           |ses2            |0             |1              |
|9           |ses2            |0             |2              |
+------------+----------------+--------------+---------------+

欢迎任何建议。

2 个答案:

答案 0 :(得分:1)

使用分析(windows)函数很容易:

SELECT id, session_id,ATTMPT_COUNTER,
       sum( ATTMPT_COUNTER2 ) over (partition by session_id order by id ) as accumulating 
FROM (
select id, session_id,ATTMPT_COUNTER,
       case ATTMPT_COUNTER 
            when lag( ATTMPT_COUNTER ) over (partition by session_id order by id )
            then 1 else 0
        end As ATTMPT_COUNTER2
from table1 t
)
order by id
;

如果您不喜欢Windows功能,请尝试以下操作:

WITH subquery AS (
    SELECT id, session_id,ATTMPT_COUNTER,
           case ATTMPT_COUNTER
           when ( SELECT ATTMPT_COUNTER FROM table1 t1
                  WHERE t1.session_id  = t.session_id
                    AND t1.id < t.id
                  ORDER BY id DESC
                  FETCH first row only
                  )
            then 1 else 0 end as ATTMPT_COUNTER2
    FROM table1 t
)
SELECT s1.id, s1.session_id, sum( s2.ATTMPT_COUNTER2 ) as accumulating 
FROM subquery s1
JOIN subquery s2 
ON s1.session_id = s2.session_id AND s1.id >= s2.id
GROUP BY s1.id, s1.session_id
order by id

如果您也不喜欢WITH子句(公用表表达式),则必须以这种方式复制子查询:

SELECT s1.id, s1.session_id, sum( s2.ATTMPT_COUNTER2 ) as accumulating 
FROM (
   SELECT id, session_id,ATTMPT_COUNTER,
           case ATTMPT_COUNTER
           when ( SELECT ATTMPT_COUNTER FROM table1 t1
                  WHERE t1.session_id  = t.session_id
                    AND t1.id < t.id
                  ORDER BY id DESC
                  FETCH first row only
                  )
            then 1 else 0 end as ATTMPT_COUNTER2
    FROM table1 t
)s1
JOIN (
   SELECT id, session_id,ATTMPT_COUNTER,
           case ATTMPT_COUNTER
           when ( SELECT ATTMPT_COUNTER FROM table1 t1
                  WHERE t1.session_id  = t.session_id
                    AND t1.id < t.id
                  ORDER BY id DESC
                  FETCH first row only
                  )
            then 1 else 0 end as ATTMPT_COUNTER2
    FROM table1 t
) s2 
ON s1.session_id = s2.session_id AND s1.id >= s2.id
GROUP BY s1.id, s1.session_id
order by id

FETCH first row only子句(ANSII SQL变体)适用于Oracle 12c和DB2,其他数据库使用LIMIT 1子句(不符合ANSII SQL)。

答案 1 :(得分:0)

使用LAGSUM分析函数:首先检查前一行的尝试计数器是否大于当前行的计数器;然后总计每个会话的当前行和所有先前行的访问次数。

SELECT id,
       session_id,
       attmpt_counter,
       SUM( has_accessed ) OVER ( PARTITION BY session_id ORDER BY id ) AS entrance
FROM   (
  SELECT t.*,
         CASE
         WHEN LAG( attmpt_counter ) OVER ( PARTITION BY session_id ORDER BY id )
                >= attmpt_counter
         THEN 1
         ELSE 0 
         END  AS has_accessed
  FROM   table_name t
);