OutlineNumber の深さはまだわからないので、parsename を使用した 4 部構成のバージョン番号の通常の順序に基づいて解決策を提供します。
;with VNums as (
select PID
, Task
, OutlineNumber
, OutlineNumber + replicate('.0', 3 - (len(OutlineNumber) - len(replace(OutlineNumber, '.', '')))) as VNum
from MyTable
), VOrders as (
select PID
, Task
, OutlineNumber
, VNum
, row_number() over (order by cast(parsename(VNum, 4) as int), cast(parsename(VNum, 3) as int), cast(parsename(VNum, 2) as int), cast(parsename(VNum, 1) as int)) as VOrder
from VNums
)
select PID
, Task
, parsename(VNum, 4) as CatID
, case when OutlineNumber not like '%.%' then null else VOrder - 1 end as SubCatID
from VOrders
order by VOrder;
これにより、次の結果が得られます。
PID Task CatID SubCatID
------------------------------
1 Task1 0 NULL
2 Task2 1 NULL -- 1 in OP's example
3 Task3 1 2
4 Task4 1 3
5 Task5 2 NULL
6 Task6 2 5
7 Task7 2 6
SubCatID をバージョン番号の全体的なゼロベースのインデックスに設定しているだけですが、「.」がない場合は null です。または「マイナーバージョン」。
私は@Lamakのコメントを2番目にし、Task2とTask5のSubCatIDが両方ともnullではないことを確認できないことを認めます(「0のSubCatIDがないため、次のCatIDを非nullにする」などの推測を除く) )。
9 を超える可能性のあるノードを含め、OutlineNumber の無限の深さに移動するには、ソリューションは再帰 CTE の形式を取るか、動的 SQL を含む proc を使用する可能性があります。