Recursive/looping 查询 ROW_NUMBER 所需的帮助

Recursive/looping query help needed with ROW_NUMBER

我希望能够通过 table 的 material 秒移动、用于移动它的设备和时间来追溯,从字段中的指定值开始并找到该值基于共享值在不同行的另一个字段中。

在下面的 table 中,我需要能够回溯,例如,从 EndCode 'M' 所有相关行一直回溯到 StartCode A。然后我可能想要能够通过所有行从 EndCode 'U' 追溯到 StartCode 'N'。

在table中,StartCode(material)A和B被移动成为EndCode C。EndCode C再成为StartCodeD,再与StartCode E一起移动成为EndCode F等。 orange/blue 行代表 material 组动作。

据此,我想创建一个新的 table/view,它将下一个事件的 StartedAt 时间作为一个名为 'EndedAt' 的新字段引入。它看起来像这样:

我创建了一个递归查询,它使用 ROW_NUMBER 和 CTE 将 StartedAt 作为新字段引入 "EndedAt"。

然后我尝试使用嵌套的 SELECT 语句来查找与 EndCode 'M' 相关的所有 StartCodes,试图通过 table 环回搜索所有相关的 EndCodes在 StartCode 列中。这只会带来几行。我很害怕我重复嵌套语句几次它带来了不同的行。

我需要帮助来获取创建所需 table/view 所需的所有相关 Start/End 代码。

最终,一份报告将附加到 table,允许 table 可以通过选定的 EndCode 参数(例如 M、U​​ 等)进行过滤

    CREATE TABLE MyTable (
  `StartCode` VARCHAR(1),
  `StartedAt` DATETIME,
  `EndCode` VARCHAR(1)
);

INSERT INTO MyTable (`StartCode`, `StartedAt`, `EndCode`)
VALUES
  ('A', '01/01/2019 01:00', 'C'),
  ('B', '01/01/2019 02:15', 'C'),
  ('C', '01/01/2019 03:00', 'F'),
  ('D', '01/01/2019 03:19', 'F'),
  ('E', '01/01/2019 04:00', 'F'),
  ('F', '01/01/2019 04:14', 'G'),
  ('G', '01/01/2019 05:00', 'J'),
  ('H', '01/01/2019 05:37', 'J'),
  ('I', '01/01/2019 05:45', 'J'),
  ('J', '01/01/2019 06:00', 'L'),
  ('K', '01/01/2019 06:09', 'L'),
  ('L', '01/01/2019 07:00', 'M'),
  ('N', '01/01/2019 09:20', 'P'),
  ('O', '01/01/2019 09:37', 'P'),
  ('P', '01/01/2019 09:45', 'Q'),
  ('Q', '01/01/2019 11:00', 'T'),
  ('R', '01/01/2019 11:10', 'T'),
  ('S', '01/01/2019 11:47', 'T'),
  ('T', '01/01/2019 11:58', 'U');

EndedAt 是一个简单的连接:

SELECT
    S.StartCode,
    S.StartedAt,
    S.EndCode,
    E.StartedAt AS EndedAt
FROM
    MyTable AS S
    LEFT JOIN MyTable AS E ON S.EndCode = E.StartCode

结果:

StartCode   StartedAt                   EndCode     EndedAt
A           2019-01-01 01:00:00.000     C           2019-01-01 03:00:00.000
B           2019-01-01 02:15:00.000     C           2019-01-01 03:00:00.000
C           2019-01-01 03:00:00.000     F           2019-01-01 04:14:00.000
D           2019-01-01 03:19:00.000     F           2019-01-01 04:14:00.000
E           2019-01-01 04:00:00.000     F           2019-01-01 04:14:00.000
F           2019-01-01 04:14:00.000     G           2019-01-01 05:00:00.000
G           2019-01-01 05:00:00.000     J           2019-01-01 06:00:00.000
H           2019-01-01 05:37:00.000     J           2019-01-01 06:00:00.000
I           2019-01-01 05:45:00.000     J           2019-01-01 06:00:00.000
J           2019-01-01 06:00:00.000     L           2019-01-01 07:00:00.000
K           2019-01-01 06:09:00.000     L           2019-01-01 07:00:00.000
L           2019-01-01 07:00:00.000     M           NULL
N           2019-01-01 09:20:00.000     P           2019-01-01 09:45:00.000
O           2019-01-01 09:37:00.000     P           2019-01-01 09:45:00.000
P           2019-01-01 09:45:00.000     Q           2019-01-01 11:00:00.000
Q           2019-01-01 11:00:00.000     T           2019-01-01 11:58:00.000
R           2019-01-01 11:10:00.000     T           2019-01-01 11:58:00.000
S           2019-01-01 11:47:00.000     T           2019-01-01 11:58:00.000
T           2019-01-01 11:58:00.000     U           NULL

您可以使用以下内容显示层次结构(在本例中为自下而上方法的递归 CTE)。首先确保您的数据中没有循环。

编辑: 如果你想检查层次结构中的任何步骤和向上,锚点需要是任何代码(不仅仅是最后的 MU), 所以我删除了锚点中的 WHERE.

DECLARE @EndCodeFilter CHAR(1) = 'J'

;WITH RecursiveCodes AS
(
    -- Anchor
    SELECT
        LastCode = M.EndCode,
        CurrentCode = M.StartCode,
        PreviousCode = M.EndCode,
        RecursionLevel = 1,
        RecursionPath = CONVERT(NVARCHAR(MAX), M.EndCode + '->' + M.StartCode),
        CurrentStartAt = M.StartedAt
    FROM
        MyTable AS M

    UNION ALL

    -- Recursion: link related codes
    SELECT
        LastCode = R.LastCode,
        CurrentCode = M.StartCode,
        PreviousCode = M.EndCode,
        RecursionLevel = R.RecursionLevel + 1,
        RecursionPath = R.RecursionPath + '->' + M.StartCode,
        CurrentStartAt = M.StartedAt
    FROM
        RecursiveCodes AS R
        INNER JOIN MyTable AS M ON R.CurrentCode = M.EndCode
)
SELECT
    R.CurrentCode,
    R.CurrentStartAt,
    R.LastCode,
    EndedAt = E.StartedAt,
    R.PreviousCode,
    R.RecursionLevel,
    R.RecursionPath
FROM
    RecursiveCodes AS R
    LEFT JOIN MyTable AS E ON R.LastCode = E.StartCode
WHERE
    R.LastCode = @EndCodeFilter
ORDER BY
    R.CurrentCode,
    R.LastCode
OPTION
    (MAXRECURSION 0)

结果:

CurrentCode CurrentStartAt              LastCode    EndedAt                     PreviousCode    RecursionLevel  RecursionPath
A           2019-01-01 01:00:00.000     J           2019-01-01 06:00:00.000     C               4               J->G->F->C->A
B           2019-01-01 02:15:00.000     J           2019-01-01 06:00:00.000     C               4               J->G->F->C->B
C           2019-01-01 03:00:00.000     J           2019-01-01 06:00:00.000     F               3               J->G->F->C
D           2019-01-01 03:19:00.000     J           2019-01-01 06:00:00.000     F               3               J->G->F->D
E           2019-01-01 04:00:00.000     J           2019-01-01 06:00:00.000     F               3               J->G->F->E
F           2019-01-01 04:14:00.000     J           2019-01-01 06:00:00.000     G               2               J->G->F
G           2019-01-01 05:00:00.000     J           2019-01-01 06:00:00.000     J               1               J->G
H           2019-01-01 05:37:00.000     J           2019-01-01 06:00:00.000     J               1               J->H
I           2019-01-01 05:45:00.000     J           2019-01-01 06:00:00.000     J               1               J->I