Sql 作为输入,使用匹配\u识别: select id, item, listagg(item_loc, ',') within group(order by first_loc) item_loc from t match_recognize( partition by id, item order by loc measures a.loc first_loc, a.loc || case count(*) when 1 then null else '-'||b.loc end item_loc pattern (a b*) define b as loc = prev(loc) + 1 ) group by id, item; ID ITEM ITEM_LOC 1 Item-1 0-1 2 Item-2 0-4,7 3 Item-3 0-48 4 Item-4 0-8 5 Item-5 1-33 6 Item-6 0-1 7 Item-7 1,5,7-11

Sql 作为输入,使用匹配\u识别: select id, item, listagg(item_loc, ',') within group(order by first_loc) item_loc from t match_recognize( partition by id, item order by loc measures a.loc first_loc, a.loc || case count(*) when 1 then null else '-'||b.loc end item_loc pattern (a b*) define b as loc = prev(loc) + 1 ) group by id, item; ID ITEM ITEM_LOC 1 Item-1 0-1 2 Item-2 0-4,7 3 Item-3 0-48 4 Item-4 0-8 5 Item-5 1-33 6 Item-6 0-1 7 Item-7 1,5,7-11,sql,oracle,plsql,oracle12c,Sql,Oracle,Plsql,Oracle12c,请注意,此处的输出与输入不完全相同,因为任何连续整数都将压缩为一对。永远不要将数据存储为逗号分隔的项。这只会给您带来很多麻烦。“不能重复使用”是否意味着该函数还应该删除从列中存储的列表中返回的ID(即同时更新表)@jarlh-完全同意您的意见,但这是预先存在的数据。@没有名称的“马”不能重复使用表示ID可以重复使用,但ITEM_LOC列中的值(如果已使用)不能再次使用。例如,我只能使用该ID的ITEM_LOC值六次,即0,1,2,3,4,7。如果我使用了0,那么我的下一个可用值将是1,依此类推。

请注意,此处的输出与输入不完全相同,因为任何连续整数都将压缩为一对。

永远不要将数据存储为逗号分隔的项。这只会给您带来很多麻烦。“不能重复使用”是否意味着该函数还应该删除从列中存储的列表中返回的ID(即同时更新表)@jarlh-完全同意您的意见,但这是预先存在的数据。@没有名称的“马”不能重复使用表示ID可以重复使用,但ITEM_LOC列中的值(如果已使用)不能再次使用。例如,我只能使用该ID的ITEM_LOC值六次,即0,1,2,3,4,7。如果我使用了0,那么我的下一个可用值将是1,依此类推。希望这是有意义的。但是你在哪里存储使用ID的信息呢?从列表中删除已使用的数据库似乎是唯一的选择(考虑到您的数据库设计已损坏)。或者您是否有另一个存储所用值的表?永远不要将数据存储为逗号分隔的项。这只会给您带来很多麻烦。“不能重复使用”是否意味着该函数还应该删除从列中存储的列表中返回的ID(即同时更新表)@jarlh-完全同意您的意见,但这是预先存在的数据。@没有名称的“马”不能重复使用表示ID可以重复使用,但ITEM_LOC列中的值(如果已使用)不能再次使用。例如,我只能使用该ID的ITEM_LOC值六次,即0,1,2,3,4,7。如果我使用了0,那么我的下一个可用值将是1,依此类推。希望这是有意义的。但是你在哪里存储使用ID的信息呢?从列表中删除已使用的数据库似乎是唯一的选择(考虑到您的数据库设计已损坏)。或者您是否有另一个存储已用值的表?请参阅我在上面对@a_horse_的注释,其中包含关于“无法再次使用项目位置”的注释。您好@tonyf如果您可以使用此答案以及下面链接中的答案,您可以删除不再使用的项目,请参阅我在上面对@a_horse_的注释,其中包含关于“无法再次使用项目位置”的注释“无法再次使用物品”。Hi@tonyf您可以使用此答案以及下面链接中的答案,您可以删除不再使用的物品
SQL> with my_data (id, item, item_loc) as
  2    (select 2, 'Item-2', '0,2,4,7' from dual union all
  3     select 7, 'Item-7', '0,1,5'   from dual union all
  4     select 3, 'Item-3', '0-4'     from dual union all
  5     select 8, 'Item-8', '5-8'     from dual
  6    )
  7  select id,
  8    item,
  9    regexp_substr(item_loc, '[^,]+', 1, column_value) loc
 10  from my_data
 11    cross join table(cast(multiset
 12      (select level from dual
 13       connect by level <= regexp_count(item_loc, ',') + 1
 14      ) as sys.odcinumberlist))
 15  where instr(item_loc, '-') = 0
 16  union all
 17  select id,
 18    item,
 19    to_char(to_number(regexp_substr(item_loc, '^\d+')) + column_value - 1) loc
 20  from my_data
 21    cross join table(cast(multiset
 22      (select level from dual
 23       connect by level <= to_number(regexp_substr(item_loc, '\d+$')) -
 24                           to_number(regexp_substr(item_loc, '^\d+')) + 1
 25      ) as sys.odcinumberlist))
 26  where instr(item_loc, '-') > 0
 27  order by id, item, loc;

        ID ITEM   LOC
---------- ------ ----------------------------------------
         2 Item-2 0
         2 Item-2 2
         2 Item-2 4
         2 Item-2 7
         3 Item-3 0
         3 Item-3 1
         3 Item-3 2
         3 Item-3 3
         3 Item-3 4
         7 Item-7 0
         7 Item-7 1
         7 Item-7 5
         8 Item-8 5
         8 Item-8 6
         8 Item-8 7
         8 Item-8 8

16 rows selected.

SQL>
create table t as 
with input(id, item, item_loc) as (
  select 1, 'Item-1', ' 0,1' from dual union all
  select 2, 'Item-2', '0,1,2,3,4,7' from dual union all
  select 3, 'Item-3', '0-48' from dual union all
  select 4, 'Item-4', '0,1,2,3,4,5,6,7,8' from dual union all
  select 5, 'Item-5', '1-33' from dual union all
  select 6, 'Item-6', '0,1' from dual union all
  select 7, 'Item-7', '0,1,5,8,7 - 11' from dual
)
select distinct id, item, loc from input, xmltable(
 'let $item := if (contains($X,",")) then ora:tokenize($X,"\,") else $X
  for $i in $item
    let $j := if (contains($i,"-")) then ora:tokenize($i,"\-") else $i
    for $k in xs:int($j[1]) to xs:int($j[count($j)])
    return $k'
  passing item_loc as X
  columns loc number path '.'
);
delete from t where rowid = (
  select min(rowid) keep (dense_rank first order by loc)
  from t
  where id = 7
);
select id, item, listagg(item_loc, ',') within group(order by first_loc) item_loc
from t
match_recognize(
  partition by id, item order by loc
  measures a.loc first_loc,
    a.loc || case count(*) when 1 then null else '-'||b.loc end item_loc
  pattern (a b*)
  define b as loc = prev(loc) + 1
)
group by id, item;

ID  ITEM    ITEM_LOC
1   Item-1  0-1
2   Item-2  0-4,7
3   Item-3  0-48
4   Item-4  0-8
5   Item-5  1-33
6   Item-6  0-1
7   Item-7  1,5,7-11