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
请注意,此处的输出与输入不完全相同,因为任何连续整数都将压缩为一对。永远不要将数据存储为逗号分隔的项。这只会给您带来很多麻烦。“不能重复使用”是否意味着该函数还应该删除从列中存储的列表中返回的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 作为输入,使用匹配\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,依此类推。
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