I started fiddle , which will provide you with a list of available "open" tags by element. It does this with #tags (AllTags) and does outer-join-where-null . You can use this to insert new tags from T_New ...
with T_openTags as ( select items.item, openTagName = a.tag from (select distinct item from T) items cross join AllTags a left outer join T on items.item = T.item and T.tag = a.tag where T.item is null ) select * from T_openTags
or see this updated script to do an update on the T_New table. Essentially adds row_number, so we can choose the right open tag to use in a single update statement. I have simplified sorting by tag names with a leading zero.
with T_openTags as ( select items.item, openTagName = a.tag, rn = row_number() over(partition by items.item order by a.tag) from (select distinct item from T) items cross join AllTags a left outer join T on items.item = T.item and T.tag = a.tag where T.item is null ), T_New_numbered as ( select *, rn = row_number() over(partition by item order by value) from T_New ) update tnn set tag = openTagName from T_New_numbered tnn inner join T_openTags tot on tot.item = tnn.item and tot.rn = tnn.rn select * from T_New
updated fiddle with poor row_number string replacement that only works with different T_New values
source share