【问题标题】:Recursive/looping query help needed with ROW_NUMBERROW_NUMBER 需要递归/循环查询帮助
【发布时间】:2019-01-09 12:33:16
【问题描述】:

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

在下表中,我需要能够追溯,例如,从 EndCode 'M' 所有相关行一直追溯到 StartCode A。然后我可能希望能够追溯所有从 EndCode 'U' 返回到 StartCode 'N' 的行。

在表格中,StartCode(材料)A 和 B 移动成为 EndCode C。EndCode C 然后成为 StartCodeD,然后与 StartCode E 一起移动成为 EndCode F 等等。橙色/蓝色行代表材料移动组。

据此,我想创建一个新的表/视图,它将下一个事件的 StartedAt 时间作为一个名为“EndedAt”的新字段。它看起来像这样:

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

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

我需要帮助来获取创建所需表/视图所需的所有相关开始/结束代码。

最终会在表格中附加一份报告,允许表格可以通过所选的 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');

【问题讨论】:

  • 最好将您的示例数据提供为formatted text,或者更好的是,在 sql fiddle 中。这让我们更容易为您提供帮助。
  • EndedAt 列是一个简单直接的连接(不需要递归也不需要 CTE)。对于 M 到 A,如果您可以发布完整的 DML 和 DDL 示例,我可以为您提供帮助。还要删除存储桶列,因为它们对您的问题并不重要。
  • 请从层次关系中指定您想要的确切输出。
  • 好的,用过 SL Fiddle,见编辑。谢谢:)

标签: sql-server loops recursive-query row-number ssms-2017


【解决方案1】:

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

【讨论】:

  • 我试试看。谢谢,Ezlo。我能看到的唯一问题是,如果根据我在初始帖子中的示例,例如,我只想追溯链接到 EndCode M 和 EndCode 的所有 Start/EndCodes 并显示您在第一篇文章中列出的信息结果集。唯一的方法是按照从字母 M 到 A 的 Stat/EndCodes,我不能用你做(非常感谢)帮助?
  • 层次结构代码有效,必须将 CONVERT 部分更改为 NVARCHAR 而不是 VARCHAR 并且它有效。我只需要能够在您的第一个输出中显示一个表格,我可以说“只显示与 EndCode M 相关的那些行”。我想使用一个使用 EndCode 字段的@parameter 作为可供选择的值。
  • @Jimbo 我已经编辑了参数查询的答案。
  • 感谢@EnZo 的所有帮助。问题是每一行的 EndedAt 应该是下一行的 StartedAt 值,目前它只带来每行的最后一个 StartedAt 日期。此外,如果将参数字母 J 更改为字母 M 或 U,则 EndedAt 值全部为 Null。
  • @Jimbo 我相信您现在可以编辑查询以满足您的需求。此外,M 和 U 没有时间戳,因此您永远不会知道它们的结束日期。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-26
  • 1970-01-01
  • 2011-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多