SQL Server:父/子 - 查找状态失败的最深的孩子

时间:2016-12-14 15:38:28

标签: sql sql-server tsql

我有下表:

STEPID|RUN_ID|SERIAL |PARENT|STEPNAME                                  |STATUS
171730|  3101|0103107|171696|6.9 - Load Program YXZ                    |Failed
171740|  3101|0103107|171730|6.9.5 - Step Test. Program YXZ Error Code |Failed
171741|  3101|0103107|171730|6.9.6 - Step Test. Program YXZ - Part 1   |Failed
171742|  3101|0103107|171730|6.9.7 - Step Test. Program YXZ - Part 2   |Failed
171743|  3101|0103107|171730|6.9.8 - Step Test. Program YXZ - Part 3   |Failed
171744|  3101|0103107|171730|6.9.9 - Step Test. Program YXZ - Part 4   |Failed
171745|  3101|0103107|171730|6.9.10 - Step Test. Program YXZ - Part 5  |Failed
171785|  3102|0103107|171751|6.9 - Load Program YXZ                    |Failed
171788|  3102|0103107|171785|6.9.4 - Run Test - Monitor                |Failed
171789|  3102|0103107|171788|6.9.4.1 - Step Test. Program YXZ - Part 11|Failed
171790|  3102|0103107|171788|6.9.4.2 - Step Test. Program YXZ - Part 12|Failed
171791|  3102|0103107|171788|6.9.4.3 - Step Test. Program YXZ - Part 13|Failed
171792|  3102|0103107|171788|6.9.4.4 - Step Test. Program YXZ - Part 14|Failed
171793|  3102|0103107|171788|6.9.4.5 - Step Test. Program YXZ - Part 15|Failed
171794|  3102|0103107|171788|6.9.4.6 - Step Test. Program YXZ - Part 16|Failed
171795|  3102|0103107|171785|6.9.5 - Step Test. Program YXZ Error Code |Failed
171796|  3102|0103107|171785|6.9.6 - Step Test. Program YXZ - Part 1   |Failed
171797|  3102|0103107|171785|6.9.7 - Step Test. Program YXZ - Part 2   |Failed
171798|  3102|0103107|171785|6.9.8 - Step Test. Program YXZ - Part 3   |Failed
171799|  3102|0103107|171785|6.9.9 - Step Test. Program YXZ - Part 4   |Failed
171800|  3102|0103107|171785|6.9.10 - Step Test. Program YXZ - Part 5  |Failed

对于同一个序列,我有2个唯一的RUN_ID#。 Foreach RUN_ID,我需要找到最深层次的孩子,状态失败。从上表我想找到:

STEPID|RUN_ID|SERIAL |PARENT|STEPNAME                                  |STATUS
171745|  3101|0103107|171730|6.9.10 - Step Test. Program YXZ - Part 5  |Failed
171794|  3102|0103107|171788|6.9.4.6 - Step Test. Program YXZ - Part 16|Failed
171800|  3102|0103107|171785|6.9.10 - Step Test. Program YXZ - Part 5  |Failed

6.9可能是一个有效的孩子,但因为它有状态失败的孩子,所以需要将其排除在外。我不希望等级超过4,如6.9.4.6。

有可能在纯SQL中解决这个问题吗?我试图对级别层次结构进行子串,并将其作为单独的列公开,并按/ CTE进行一些分组,但我无法理解它。

STEPID|RUN_ID|SERIAL |PARENT|Level1|Level2|Level3|Level4|STATUS
171785|  3102|0103107|171751|     6|     9|  NULL|  NULL|Failed
171788|  3102|0103107|171785|     6|     9|     4|  NULL|Failed
171789|  3102|0103107|171788|     6|     9|     4|     1|Failed
171790|  3102|0103107|171788|     6|     9|     4|     2|Failed

更新#1: Anand询问步骤名是否以单个数字开头。它在真实的桌子上,但我已经在我当前的CTE中过滤掉了,因为在该级别上不会发生错误。

更新#2: 用于创建表(伪造CTE)和插入语句的粘贴bin链接:http://pastebin.com/7JmP99KP

1 个答案:

答案 0 :(得分:2)

它有点长时间将子节点解析为一个整数而不是最终复制/粘贴speghetti,但至少你可以逐个走CTE以了解我是如何到达那里的。

WITH
    StepWithTrimmedName AS
    (
        SELECT
            *,
            SUBSTRING(s.STEPNAME, 1, CHARINDEX(' - ', s.STEPNAME) - 1) AS TrimmedName
        FROM
            dbo.Temp_Steps s
    ),
    StepWithPeriod AS
    (
        SELECT
            *,
            CHARINDEX('.', REVERSE(s.TrimmedName)) AS Period
        FROM
            StepWithTrimmedName s
    ),
    StepWithCharacterLength AS
    (
        SELECT
            *,
            CASE
                WHEN s.Period = 0 THEN 1
                ELSE s.Period - 1
            END AS CharacterLength
        FROM
            StepWithPeriod s
    ),
    StepWithStartPosition AS
    (
        SELECT
            *,
            LEN(s.TrimmedName) - s.CharacterLength + 1 AS StartPosition
        FROM
            StepWithCharacterLength s
    ),
    StepWithRowNumber AS
    (
        SELECT
            *,
            ROW_NUMBER() OVER (PARTITION BY s.PARENT ORDER BY
                CAST(SUBSTRING(s.TrimmedName, s.StartPosition, s.CharacterLength) AS INT) DESC) AS RowNum
        FROM
            StepWithStartPosition s
        WHERE
            s.[Status] = 'Failed'
    )
SELECT
    *
FROM
    StepWithRowNumber s
WHERE
    s.RowNum = 1 AND
    NOT EXISTS
    (
        SELECT *
        FROM
            StepWithRowNumber c
        WHERE
            c.PARENT = s.StepId
    )
ORDER BY
    S.SERIAL,
    s.RUN_ID,
    s.PARENT,
    s.RowNum;