sql - 具有基于滞后条件的 Oracle SQL ROW_NUMBER() 窗口

标签 sql oracle

使用仅具有选择权限的 Oracle SQL,我需要根据条件提供 ROW_NUMBER 输出。使用游标或循环这会很简单,但目前我必须只使用 SQL 来执行此任务。

我一直在修补 row_number() over 子句,我认为这是正确的方法,但我现在卡住了。

我当前的代码 - 或者至少是它的代理:

    WITH MYTABLE (FK_ID,FK_NAME,PK_ID,BIN_FLAG,MONTH,YEAR)AS (
      SELECT 10000,'VARCHAR DESCRIPTION',75057,1,1,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,1,2,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,1,3,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,4,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,1,5,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,6,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,7,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,1,8,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,9,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,10,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,1,11,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,12,2016 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,1,2017 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,2,2017 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,3,2017 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,4,2017 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,5,2017 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,6,2017 FROM DUAL
UNION SELECT 10000,'VARCHAR DESCRIPTION',75057,0,7,2017 FROM DUAL

)

SELECT
   FK_ID
,  FK_NAME
,  PK_ID
,  BIN_FLAG
,  ROW_NUMBER() OVER (PARTITION BY FK_ID,PK_ID,BIN_FLAG ORDER BY YEAR,MONTH,FK_ID,PK_ID ASC) NEEDED_CALC
,  MONTH
,  YEAR
FROM MYTABLE
ORDER BY FK_ID,PK_ID,YEAR,MONTH

这将返回一个看起来像这样的数据集:

FK_ID   FK_NAME             PK_ID       BIN_FLAG    NEEDED_CALC MONTH   YEAR
10000   VARCHAR DESCRIPTION 75057       1           1           1       2016
10000   VARCHAR DESCRIPTION 75057       1           2           2       2016
10000   VARCHAR DESCRIPTION 75057       1           3           3       2016
10000   VARCHAR DESCRIPTION 75057       0           1           4       2016
10000   VARCHAR DESCRIPTION 75057       1           4           5       2016
10000   VARCHAR DESCRIPTION 75057       0           2           6       2016
10000   VARCHAR DESCRIPTION 75057       0           3           7       2016
10000   VARCHAR DESCRIPTION 75057       1           5           8       2016
10000   VARCHAR DESCRIPTION 75057       0           4           9       2016
10000   VARCHAR DESCRIPTION 75057       0           5           10      2016
10000   VARCHAR DESCRIPTION 75057       1           6           11      2016
10000   VARCHAR DESCRIPTION 75057       0           6           12      2016
10000   VARCHAR DESCRIPTION 75057       0           7           1       2017
10000   VARCHAR DESCRIPTION 75057       0           8           2       2017
10000   VARCHAR DESCRIPTION 75057       0           9           3       2017
10000   VARCHAR DESCRIPTION 75057       0           10          4       2017
10000   VARCHAR DESCRIPTION 75057       0           11          5       2017
10000   VARCHAR DESCRIPTION 75057       0           12          6       2017
10000   VARCHAR DESCRIPTION 75057       0           13          7       2017

我需要的是 NEEDED_CALC 列,以便在上个月的 bin_flag 更改时随时重置计算。

因此,如果 bin_flag = 1 和前一个月的 bin_flag(通过 lag 函数识别)不同,则计数器列在NEEDED_CALC 将重置并从 1 开始。

最佳答案

这是一个“差距和孤岛”问题。关键是将组标识符分配给具有相同值的相邻行。有两种简单的方法可以做到这一点:一种是基于 lag(),另一种是 row_number() 的差异。

第二个稍微简单一点,只需要一级子查询:

select t.*,
       row_number() over (partition by fk_id, bin_flag, seqnum_ym - seqnum_bym
                          order by year, month
                         ) as needed_calc
from (select t.*,
             row_number() over (partition by fk_id order by year, month) as seqnum_ym,
             row_number() over (partition by fk_id order by bin_flag, year, month) as seqnum_bym
      from mytable t
     ) t;

行号的差异并不难理解,但确实需要概念上的飞跃。我建议您运行子查询并查看 seqnum_ymseqnum_bym 的值是什么,以了解其工作原理。

关于sql - 具有基于滞后条件的 Oracle SQL ROW_NUMBER() 窗口,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38230575/

相关文章:

php - SQL可以对update进行计算吗?

sql - 用排序重构 Ruby on Rails link_to

php - MySQL从多个表查询?

sql - 在 group by 子句中使用 min 和 max

SQL 连接和输出格式

sql - Oracle PL/SQL 中的 For In 循环

mysql - 加入树表并根据日期层次结构获取最后状态

sql - Firebird(如何使用 SQL 查找父类别)

java - Oracle 11g 和数据库连接

oracle - SAS 到 Oracle ODBC - 将 SAS 表传递到数据库