获取前一行的 ID,该行的 ID 并不总是在相关行之前的静态行数?

Get the ID of a previous row that is not always a static number of rows before the row in question?

我知道我的问题听起来很笼统,但我无法在不写一段话的情况下指定标题中的所有细节。我会尽量在这里直截了当。

我有一个 forms/ordered form-items 的数据库 table。每个form-item可以缩进某个'level'。例如,缩进级别 (IL) = 0 的所有行都是该表单上的 top-level 项。如果 IL = 1,并且直接出现在 IL = 0 行之后,则 IL1 行的 parent 将是前一个 IL0 行。但是,可以有 X 个 IL1 项目,它们的 parent 都是相同的前一个 IL0。这种模式可以继续向下到 6 层嵌套(其中 IL6 的 parent 将是之前的 IL5)

这是一个表单示例,其中包含我手动填写的正确 ParentItemID(这是我尝试动态计算的列):

ItemID     FormID     SortOrder     Indent     Description          ParentItemID
1000       1          1             0          Main Item 1          NULL
1001       1          2             0          Main Item 2          NULL
1002       1          3             1          Sub Item 1           1001
1003       1          4             1          Sub Item 2           1001     
1004       1          5             2          Sub Item 2-1         1003
1005       1          6             2          Sub Item 2-2         1003
1006       1          7             2          Sub Item 2-3         1003
1007       1          8             3          Sub Item 2-3-1       1006
1008       1          9             1          Sub Item 3           1001
1009       1          10            0          Main Item 3          NULL

下面是将数据库中的原始数据实际转换为表格时的样子,就像一个可视化示例:

我正在尝试使用 LAG,它适用于第一个 IL1 项目,但从那里开始,以下每个项目都引用前一行。我想我可以 运行 一堆更新,过滤到每个缩进级别,但这并不理想。我看到 LAG 采用偏移参数,但出于某种原因,我无法理解如何动态计算它以始终引用缩进级别小于 1 的前一个项目(基于排序顺序)当前缩进级别。

这是创建 table 并填充数据的 sql:

create table FormItems(
    ItemID int,     
    FormID int,
    SortOrder int,
    Indent int,
    Description nvarchar(100),
    ParentItemID int
    )

insert into FormItems
select 1000,       1,          1 ,            0,          'Main Item 1'          ,NULL union
select 1001,       1,          2 ,            0,          'Main Item 2'          ,NULL union
select 1002,       1,          3 ,            1,          'Sub Item 1'           ,1001 union
select 1003,       1,          4 ,            1,          'Sub Item 2'           ,1001 union     
select 1004,       1,          5 ,            2,          'Sub Item 2-1'         ,1003 union
select 1005,       1,          6 ,            2,          'Sub Item 2-2'         ,1003 union
select 1006,       1,          7 ,            2,          'Sub Item 2-3'         ,1003 union
select 1007,       1,          8 ,            3,          'Sub Item 2-3-1'       ,1006 union
select 1008,       1,          9 ,            1,          'Sub Item 3'           ,1001 union
select 1009,       1,          10,            0,          'Main Item 3'          ,NULL

可能最简单的方法是应用:

select t.*, tp.itemId
from t outer apply
     (select top (1) tp.*
      from t tp
      where tp.formId = t.formId and
            tp.indent = t.indent - 1 and
            tp.sortorder < t.sortorder
      order by tp.sortorder desc
     ) tp;