【问题标题】:Oracle partition by group into date based sequenceOracle 按组划分为基于日期的序列
【发布时间】:2013-02-22 08:00:59
【问题描述】:

我正在尝试使用 PARTITION BY OVER 按某些列“分组”行。我对 PARTITION 的使用有所了解,但是我想按日期“阻止”分区。例如,如果我们有

|col1|col2       |
| A  |01/JAN/2012|
| A  |01/FEB/2012|
| B  |01/MAR/2012|
| B  |01/APR/2012|
| A  |01/MAY/2012|

我想按 col1 进行分区,但我希望最后一个 A 与前两个“不同”,因为它在日期方面被“B”行分隔。

如果我使用;

SELECT ROW_NUMBER() OVER (PARTITION BY col1 ORDER BY col2) AS RNUM, a.* 
FROM table1 a;

它会产生;

|RNUM|col1|col2       |
|   1| A  |01/JAN/2012|
|   2| A  |01/FEB/2012|
|   3| A  |01/MAY/2012|
|   1| B  |01/MAR/2012|
|   2| B  |01/APR/2012|

但我真正想要的是;

|RNUM|col1|col2       |
|   1| A  |01/JAN/2012|
|   2| A  |01/FEB/2012|
|   1| B  |01/MAR/2012|
|   2| B  |01/APR/2012|
|   1| A  |01/MAY/2012|

这可以使用 PARTITION BY OVER 吗?目前我已经退回到使用游标来解析数据并分配一个组 id,这样我就可以分隔两个“A”序列,但这很慢。

谢谢,

标记。

【问题讨论】:

    标签: sql oracle analytic-functions


    【解决方案1】:

    您不需要分区。您需要将日期转换为 DD/MM/YYYY 格式并订购它们。或者,如果必须,那么您可以按 MM 部分进行分区,这将为您提供 01,02,03... 并且可以根据需要进行分区并轻松转换为数字。但是您不需要所有这些……不要使您的查询复杂化。始终保持简单。外部查询只是将您的日期重新格式化为 DD/MON/YYYY 格式:

    SELECT val, to_char(to_date(dt, 'DD/MM/YYYY'), 'DD/MON/YYYY') formatted_date 
      FROM
    ( -- Format your date to DD/MM/YYYY and order by it --
    SELECT 'A' val, to_char(to_date('01/JAN/2012'), 'DD/MM/YYYY') dt FROM dual  
     UNION
    SELECT 'A', to_char(to_date('01/FEB/2012'), 'DD/MM/YYYY') FROM dual  
     UNION
    SELECT 'B',to_char(to_date('01/MAR/2012'), 'DD/MM/YYYY') FROM dual  
     UNION
    SELECT 'B',to_char(to_date('01/APR/2012'), 'DD/MM/YYYY') FROM dual  
     UNION
    SELECT 'A',to_char(to_date('01/MAY/2012'), 'DD/MM/YYYY') FROM dual  
    ORDER BY 2
    )
    /
    

    您的日期按照您的意愿排序:

    VAL FORMATTED_DATE
    -------------------
    A   01/JAN/2012
    A   01/FEB/2012
    B   01/MAR/2012
    B   01/APR/2012
    A   01/MAY/2012
    

    【讨论】:

      【解决方案2】:

      请看下面我的方法,这与 Dazzal 的回答类似,逻辑略有不同:

      SQL FIDDLE

      第一步:

      --find the swhitches to new groups
      select col1, col2, 
          case when nvl(lag(col1) over (order by col2),sysdate) <> col1 then 1 end as new_grp
        from data;
      
      COL1    COL2        NEW_GRP
      A   January, 01 2012    1
      A   February, 01 2012   (null)
      B   March, 01 2012      1
      B   April, 01 2012      (null)
      A   May, 01 2012        1
      

      第二步:

      --identify/mark the groups
      
      select col1, col2, sum(new_grp) over (order by col2) as grp
      from(
        select col1, col2, 
          case when nvl(lag(col1) over (order by col2),sysdate) <> col1 then 1 end as new_grp
        from data)
        ;
      
      COL1    COL2        NEW_GRP
      A   January, 01 2012    1
      A   February, 01 2012   1
      B   March, 01 2012      2
      B   April, 01 2012      2
      A   May, 01 2012        3
      

      第三步:

      --find the row_number within group
      select col1, col2, row_number() over(partition by grp order by col2) rn
      from(
        select col1, col2, sum(new_grp) over (order by col2) as grp
        from(
          select col1, col2, 
            case when nvl(lag(col1) over (order by col2),sysdate) <> col1 then 1 end as new_grp
          from data
            )
        );
      
      COL1    COL2        NEW_GRP
      A   January, 01 2012    1
      A   February, 01 2012   2
      B   March, 01 2012      1
      B   April, 01 2012      2
      A   May, 01 2012        1
      

      【讨论】:

        【解决方案3】:

        首先,您应该为每条记录找到 GROUP_ID,以便将所有相似的 COL1 排序到不同的 GROUPS(如果它们之间有间隔)。然后在 OVER 语句中使用这个 GROUP_ID 和 COL1:

        SQLFiddle demo

        SELECT ROW_NUMBER() OVER (PARTITION BY Group_id,col1 ORDER BY col2) AS RNUM, a3.* 
        FROM 
        (
        select a1.*,
              (select count(*) from t a2 where 
               a2.col1<>a1.col1 
               AND  
               a2.col2<a1.col2) as GROUP_ID
        from t a1
        ) a3
        
        order by col2
        

        【讨论】:

        • 感谢@valex 这正是我所追求的。其他解决方案也有效,但这是最简洁的
        【解决方案4】:

        这可以通过几个分析来实现:

        select col1, col2, row_number() over (partition by grp order by col2) rnum
          from (select col1, col2, max(grp) over(order by col2) grp
                  from (select col1, col2, 
                               case 
                                 when lag(col1) over (order by col2) != col1
                                 then
                                   row_number() over (order by col2)
                                 when row_number() over(order by col2) = 1 
                                 then
                                   1
                               end grp
                          from data));
        

        即:

        首先获取col1 更改顺序的边界col2 日期:

        SQL> select col1, col2,
          2         case
          3           when lag(col1) over (order by col2) != col1
          4           then
          5             row_number() over (order by col2)
          6           when row_number() over(order by col2) = 1
          7           then
          8             1
          9         end grp
         10    from data;
        
        C COL2             GRP
        - --------- ----------
        A 01-JAN-12          1
        A 01-FEB-12
        B 01-MAR-12          3
        B 01-APR-12
        A 01-MAY-12          5
        

        然后我们可以填写这些空值:

        SQL> select col1, col2, max(grp) over(order by col2) grp
          2    from (select col1, col2,
          3                  case
          4                    when lag(col1) over (order by col2) != col1
          5                    then
          6                      row_number() over (order by col2)
          7                    when row_number() over(order by col2) = 1
          8                    then
          9                      1
         10                  end grp
         11            from data);
        
        C COL2             GRP
        - --------- ----------
        A 01-JAN-12          1
        A 01-FEB-12          1
        B 01-MAR-12          3
        B 01-APR-12          3
        A 01-MAY-12          5
        

        然后是通过col2 排序并在grp 上进行分区来分配row_number() 的情况

        小提琴:http://sqlfiddle.com/#!4/4818c/1

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2019-10-31
          • 1970-01-01
          • 2021-02-25
          • 1970-01-01
          • 2011-02-19
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多