我正在为开源工具Validation Manager创建报告。我设法在完成大量工作后提出了所有要求的报告。我正在尝试创建一个报告来列出未覆盖的报告,但是使用not in会使查询进入永无止境的处理状态。
这是DD图:
所涉及的表格位于图表的右下方。可以获得样本数据here。获得未覆盖的要求的正确方法是什么?
仅供参考:未披露的要求是那些没有相关步骤和/或其子女要求的要求。
主要问题是理论上存在无限多级别的需求关系,而SQL我只能处理2个级别。试图找出一种尽可能深入的方式。
作为参考,请参阅以下有关要求的查询(与我需要的相反):
select
c.covered, t.total
from
(SELECT DISTINCT
count(distinct unique_id) as covered
FROM
requirement
WHERE
requirement.id IN (select
requirement.id
from
`requirement` requirement
INNER JOIN `step_has_requirement` step_has_requirement ON requirement.`id` = step_has_requirement.`requirement_id`
INNER JOIN `step` step ON step_has_requirement.`step_id` = step.`id`
AND step.`test_case_id` = step_has_requirement.`step_test_case_id`
AND step.`test_case_test_id` = step_has_requirement.`step_test_case_test_id`
INNER JOIN `test_case` test_case ON step.`test_case_id` = test_case.`id`
AND test_case.`test_id` = step.`test_case_test_id`
INNER JOIN `test` test ON test_case.`test_id` = test.`id`
INNER JOIN `test_plan_has_test` test_plan_has_test ON test.`id` = test_plan_has_test.`test_id`
INNER JOIN `test_plan` test_plan ON test_plan_has_test.`test_plan_id` = test_plan.`id`
AND test_plan.`test_project_id` = test_plan_has_test.`test_plan_test_project_id`
INNER JOIN `test_project` test_project ON test_plan.`test_project_id` = test_project.`id`
INNER JOIN `requirement_status` requirement_status ON requirement.`requirement_status_id` = requirement_status.`id`
INNER JOIN `requirement_spec_node` requirement_spec_node ON requirement.`requirement_spec_node_id` = requirement_spec_node.`id`
AND requirement_spec_node.`requirement_spec_project_id` = requirement.`requirement_spec_node_requirement_spec_project_id`
AND requirement_spec_node.`requirement_spec_spec_level_id` = requirement.`requirement_spec_node_requirement_spec_spec_level_id`
AND requirement_spec_node.`requirement_spec_id` = requirement.`requirement_spec_node_requirement_spec_id`
INNER JOIN `requirement_spec` requirement_spec ON requirement_spec_node.`requirement_spec_id` = requirement_spec.`id`
AND requirement_spec.`project_id` = requirement_spec_node.`requirement_spec_project_id`
AND requirement_spec.`spec_level_id` = requirement_spec_node.`requirement_spec_spec_level_id`
INNER JOIN `project` project ON requirement_spec.`project_id` = project.`id`
WHERE
requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id}
or project.parent_project_id = $P{target_project_id}))
or requirement.id IN (select parent_requirement_id from requirement_has_requirement where parent_requirement_id = requirement.id
and requirement_id in (select
requirement.id
from
`requirement` requirement
INNER JOIN `step_has_requirement` step_has_requirement ON requirement.`id` = step_has_requirement.`requirement_id`
INNER JOIN `step` step ON step_has_requirement.`step_id` = step.`id`
AND step.`test_case_id` = step_has_requirement.`step_test_case_id`
AND step.`test_case_test_id` = step_has_requirement.`step_test_case_test_id`
INNER JOIN `test_case` test_case ON step.`test_case_id` = test_case.`id`
AND test_case.`test_id` = step.`test_case_test_id`
INNER JOIN `test` test ON test_case.`test_id` = test.`id`
INNER JOIN `test_plan_has_test` test_plan_has_test ON test.`id` = test_plan_has_test.`test_id`
INNER JOIN `test_plan` test_plan ON test_plan_has_test.`test_plan_id` = test_plan.`id`
AND test_plan.`test_project_id` = test_plan_has_test.`test_plan_test_project_id`
INNER JOIN `test_project` test_project ON test_plan.`test_project_id` = test_project.`id`
INNER JOIN `requirement_status` requirement_status ON requirement.`requirement_status_id` = requirement_status.`id`
INNER JOIN `requirement_spec_node` requirement_spec_node ON requirement.`requirement_spec_node_id` = requirement_spec_node.`id`
AND requirement_spec_node.`requirement_spec_project_id` = requirement.`requirement_spec_node_requirement_spec_project_id`
AND requirement_spec_node.`requirement_spec_spec_level_id` = requirement.`requirement_spec_node_requirement_spec_spec_level_id`
AND requirement_spec_node.`requirement_spec_id` = requirement.`requirement_spec_node_requirement_spec_id`
INNER JOIN `requirement_spec` requirement_spec ON requirement_spec_node.`requirement_spec_id` = requirement_spec.`id`
AND requirement_spec.`project_id` = requirement_spec_node.`requirement_spec_project_id`
AND requirement_spec.`spec_level_id` = requirement_spec_node.`requirement_spec_spec_level_id`
INNER JOIN `project` project ON requirement_spec.`project_id` = project.`id`
WHERE
requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id}
or project.parent_project_id = $P{target_project_id})))
order by unique_id) c,
(SELECT
count(distinct unique_id) AS total
FROM
`requirement_status` requirement_status
INNER JOIN `requirement` requirement ON requirement_status.`id` = requirement.`requirement_status_id`
INNER JOIN `requirement_spec_node` requirement_spec_node ON requirement.`requirement_spec_node_id` = requirement_spec_node.`id`
AND requirement_spec_node.`requirement_spec_id` = requirement.`requirement_spec_node_requirement_spec_id`
INNER JOIN `requirement_spec` requirement_spec ON requirement_spec_node.`requirement_spec_id` = requirement_spec.`id`
AND requirement_spec.`spec_level_id` = requirement_spec_node.`requirement_spec_spec_level_id`
AND requirement_spec.`project_id` = requirement_spec_node.`requirement_spec_project_id`
INNER JOIN `project` project ON requirement_spec.`project_id` = project.`id`
INNER JOIN `spec_level` spec_level ON requirement_spec.`spec_level_id` = spec_level.`id`
WHERE
requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id}
or project.parent_project_id = $P{target_project_id})) t
注意:SQL有一个关于我如何设法做相反的例子,得到了涵盖的要求。我想得到那些没有报道的。 SQl查询工作正常。
我正在寻找的内容与现在未涵盖的部分相同(上文)!
答案 0 :(得分:1)
你的架构是你最大的敌人。我已将SQLFiddle与您的step
表格相关联。这是一个非常令人印象深刻的表,但令人印象深刻的并不总是可以在SQL中使用。您可以很好地重构表并使它们标准化。有很多非常的情况下,将多个整数放入一个文本文件中并用逗号分隔它们是有意义的。如果您将要在该列中放入的唯一内容是由列分隔的整数,那么您将无法使您的SQL架构成为First Normal Form。虽然以这种方式设计您的架构似乎更容易,但只是在表面上才是您这样做的。实际上,你正在为自己创造一堆史诗般的比例 - 正如你现在可能正在发现的那样。由于未能满足First Normal Form,您无法利用SQL固有的任何关系权力。
修改这是一个相当大的架构。我对1NF的反应是text
的{{1}}部分。我真的不知道它的目的是什么,所以很难肯定地说,但是当我在用逗号分隔的文本框中看到多个具有相同整数列的行时,它会竖起一个大红旗。这通常表明多个列已连接成一列。在检查了模式的其他部分之后,很明显其他部分已经规范化。它似乎不是您架构中不可或缺的一部分,所以,我的错误。话虽如此,这仍然是一个非常复杂的应用程序,具有大量的交叉引用表。同时将step
和requirement_has_requirement
作为表可能会有好处,但它也有严重的缺点。
我怀疑您是否需要以当前的方式区分步骤与需求。要求不只是另一步吗?我知道您需要不同的列,但这可以通过使用step_has_requirement
和requirement_addendum
表来解决,该表可以根据需要调用,也可以在需要时忽略。我注意到您在step_addendum
中进行了版本控制。您是否预计在requirement
中需要版本?您是否预计您的某些要求会在不同时间进行版本控制?是否可以创建step
表以涵盖三个version
列,以便在version
表和相关表格中只有一个version_id
?
在任何情况下,假设您无法对此表执行任何重大操作,而您只需要提取查询...
你实际上并没有根据需要定义什么""是的,所以你需要确定什么"尽可能深的"手段。如果你有一种公式化的方法来发现这个,你可以通过创建像@RandomSeed建议的递归过程来相对容易地完成这个。如果你没有特别公式化的方法来确定什么"尽可能深的"是,您要根据客户定义的级别来确定吗?如果是这样,您仍然可以依赖存储过程。
如果您希望根据具体情况做出这些决定,或者您怀疑这些要求可能会发生变化,您还可以考虑将信息硬编码到存储元数据的MySQL表中用于您的架构。这可以允许您通过在此元数据表上运行SQL requirement
查询来确定接收回答的步数。您可以轻松地分配每个步骤或每个方案,以便进行一些您想要完成的递归。您可以在存储过程中使用此信息。
更改表格的好处是您可以创建SELECT
和step_has_requirement
的终端。然后每条记录都有一个"是" (1)或者" no" (0)确定是否涉及要求。然后,您可以在闲暇时对任何1或0的记录运行查询。
requirement_has_requirement
等
查询现在变得像在状态0和状态1之间切换一样简单,以查找记录。您可以同时查询层次结构中的所有元素。
请注意,如果requirement_has_requirement
id | status | major_version | mid_version | minor_version
.. | 0 | NULL | NULL | NULL
.. | 1 | .. | .. | ..
step_has_requirement
id | status | ...
和step
位于一个表中,并且根据它是requirement
还是{requirement
而在单独的表中包含其他列,则此操作会变得更容易并且重复次数更少{1}}。毫无疑问,这有一些缺点,但也有好处。如果您能够在第1卷之前进行这些更改,那么这可能是有益的。
你在开发中显然有一个非常复杂的应用程序。不幸的是,复杂程度超出了你的架构。没有最好的"在不对架构进行一些细微更改的情况下完成所需内容的方法。如果当前不能更改您的架构,那么我强烈建议您快速入侵,以免浪费更多时间并尽快提出调整架构的请求,然后再为您带来更大的麻烦。
答案 1 :(得分:0)
这是一团糟,但我对它采取了一个裂缝。通过使用CTE将其分解为块,您可以对较小的块进行故障排除。
;WITH
cteRequirement (id) AS
( SELECT distinct requirement.id
FROM requirement
INNER JOIN step_has_requirement
ON requirement.id = step_has_requirement.requirement_id
INNER JOIN step
ON step.id = step_has_requirement.step_id
AND step.test_case_id = step_has_requirement.step_test_case_id
AND step.test_case_test_id = step_has_requirement.step_test_case_test_id
INNER JOIN test_case
ON test_case.id = step.test_case_id
AND test_case.test_id = step.test_case_test_id
INNER JOIN test
ON test.id = test_case.test_id
INNER JOIN test_plan_has_test
ON test_plan_has_test.test_id = test.id
INNER JOIN test_plan
ON test_plan.id = test_plan_has_test.test_plan_id
AND test_plan.test_project_id = test_plan_has_test.test_plan_test_project_id
INNER JOIN test_project
ON test_project.id = test_plan.test_project_id
INNER JOIN requirement_status
ON requirement_status.id = requirement.requirement_status_id
INNER JOIN requirement_spec_node
ON requirement_spec_node.id = requirement.requirement_spec_node_id
AND requirement_spec_node.requirement_spec_project_id = requirement.requirement_spec_node_requirement_spec_project_id
AND requirement_spec_node.requirement_spec_spec_level_id = requirement.requirement_spec_node_requirement_spec_spec_level_id
AND requirement_spec_node.requirement_spec_id = requirement.requirement_spec_node_requirement_spec_id
INNER JOIN requirement_spec
ON requirement_spec.id = requirement_spec_node.requirement_spec_id
AND requirement_spec.project_id = requirement_spec_node.requirement_spec_project_id
AND requirement_spec.spec_level_id = requirement_spec_node.requirement_spec_spec_level_id
INNER JOIN project
ON project.id = requirement_spec.project_id
WHERE requirement_status.[status] = 'general.approved'
and (project.id = $P{target_project_id} or project.parent_project_id = $P{target_project_id})
),
cteParent (id) AS
( SELECT DISTINCT parent_requirement_id
FROM requirement_has_requirement
INNER JOIN cteRequirement
ON cteRequirement.id = requirement_has_requirement.requirement_id
WHERE parent_requirement_id = requirement.id
),
ListOfRequirementIDs (requirement_id) AS
( SELECT id FROM cteRequirement UNION
SELECT id FROM cteParents
),
ListOfUniqueIDs (unique_id) AS
( SELECT DISTINCT unique_id
FROM requirement_status
INNER JOIN requirement
ON requirement.requirement_status_id = requirement_status.id
INNER JOIN requirement_spec_node
ON requirement_spec_node.id = requirement.requirement_spec_node_id
AND requirement_spec_node.requirement_spec_id = requirement.requirement_spec_node_requirement_spec_id
INNER JOIN requirement_spec
ON requirement_spec_node.requirement_spec_id = requirement_spec.id
AND requirement_spec.spec_level_id = requirement_spec_node.requirement_spec_spec_level_id
AND requirement_spec.project_id = requirement_spec_node.requirement_spec_project_id
INNER JOIN project
ON project.id = requirement_spec.project_id
INNER JOIN spec_level
ON spec_level.id = requirement_spec.spec_level_id
WHERE requirement_status.status = 'general.approved'
and (project.id = $P{target_project_id} or project.parent_project_id = $P{target_project_id})
)
SELECT 'Covered' AS [Type], COUNT(ListOfRequirementIDs.requirement_id) AS Cnt
FROM ListOfRequirementIDs
UNION ALL
SELECT 'Total' AS [Type], COUNT(ListOfUniqueIDs.unique_id) AS Cnt
FROM ListOfUniqueIDs