Oracle listagg组的x行数

时间:2017-02-16 16:22:47

标签: sql oracle

我正在迁移一些数据,但在此之前我想生成一个回滚脚本。

表格中的重要列可能如下所示:

   id    code 
----- -------
 1234  121212
 1345  434343
 2345  121212
    ...

我正在将所有代码121212151515更改为252525,但如果其他地方出现问题,我需要能够将其更改回来。

所以我开始使用listagg创建逗号分隔的id列表,我可以在update语句的where子句中使用它们。这些方面的东西:

select '... set code='||code||' where id in ('
|| listagg(id,',') within group (order by id)
|| ');' as RB_STMT
from mytable
where code in (121212,151515)
group by code;

这适用于小型设备,例如在我的开发环境中,但在生产中我达到了字符串长度的限制(ORA-01489)。

所以我希望能够做的是除了代码之外还按x个id分组,这样x = 5的结果就是:

 RB_STMT
------------
...set code=121212 where id in (1234,1235,1236,1237,1238);
...set code=121212 where id in (1239,2111,2112,2123,2124);
...set code=121212 where id in (2125,2126,2136);
...set code=151515 where id in (1456,2345,2468,2469,2470);
etc.

(我当然会在现实中使用更大的x;适应ids的长度)

我尝试按floor(id/5)进行分组并修复了字符串长度问题,但由于ID不是连续的,或者是均匀间隔的,所以我最终会得到很多只有少量ID的结果,而这不是理想的。

1 个答案:

答案 0 :(得分:3)

您可以使用子查询(内联视图或CTE)将每个ID分配给存储桶,并将其包含在group-by子句中:

select '... set code='||code||' where id in ('
|| listagg(id,',') within group (order by id)
|| ');' as RB_STMT
from (
  select id, code, ceil(row_number() over (partition by code order by id)/5) as bucket
  from mytable
)
where code in (121212,151515)
group by code, bucket;

RB_STMT                                                                         
--------------------------------------------------------------------------------
... set code=121212 where id in (1234,1235,1236,1237,1238);
... set code=121212 where id in (1239,2111,2112,2123,2124);
... set code=121212 where id in (2125,2126,2136);
... set code=151515 where id in (1456,2345,2468,2469,2470);

子查询本身会产生如下输出:

        ID       CODE     BUCKET
---------- ---------- ----------
      1234     121212          1
      1235     121212          1
      1236     121212          1
      1237     121212          1
      1238     121212          1
      1239     121212          2
      1456     151515          1
      2111     121212          2
      2112     121212          2
      2123     121212          2
      2124     121212          2
      2125     121212          3
      2126     121212          3
      2136     121212          3
      2345     151515          1
      2468     151515          1
      2469     151515          1
      2470     151515          1

代码121212的前五个ID都有桶1;接下来的五个都有桶2;最后四个有桶3. 151515的桶再次从1开始。按代码和桶分组为你提供了一个简短的列表,可以聚合成最终的字符串。

要获得更多的每行,只需将5更改为更高的值。

假设在您提交更新之前,您还不知道这是一个问题,因此回滚不是一个选项 - 所以您要创建一个退出策略而不是而不是回滚' script - 其他选项包括:导出表并截断/导入,如果需要还原它;或创建表的备份副本,并还原为副本或使用它来进行更新;或者可能是其他一些我没有想过的。