假设我有一张桌子,BMST。我使用此查询来查找结果集:
SELECT PARENT,
CHILD,
LEVEL,
QTY
FROM BMST
WHERE PARENT = '111'
结果集中包含 PARENT 零件编号以及 CHILD 零件编号,例如:
PARENT | CHILD | LEVEL | QTY
-----------------------------
111 | 222 | 0 | 2
111 | 333 | 0 | 1
111 | 444 | 0 | 1
该表提供了用于制作父部件的所有子部件的信息,以及每个父部件中使用的子部件的数量。 LEVEL 列的值为“0”,因为“111”部分是我们关心的原始部分。我们不关心“111”部分是否是另一个较大父部分的子部分。
如果子零件由较小的子零件组成,则子零件也可能是父零件。例如,这个查询:
SELECT PARENT,
CHILD,
LEVEL,
QTY
FROM BMST
WHERE PARENT = '222'
会返回:
PARENT | CHILD | LEVEL | QTY
-----------------------------
222 | 555 | 1 | 1
222 | 666 | 1 | 1
222 | 777 | 1 | 1
此新表中的 LEVEL 值为“1”,因为部分“222”是 LEVEL =“0”PARENT 部分的子部分。
更进一步,“222”部分的子部分本身可以有子部分,因此对“777”部分的类似查询将返回:
PARENT | CHILD | LEVEL | QTY
-----------------------------
777 | 999 | 2 | 2
我的问题是,是否可以创建一个返回第一个结果集的查询,然后检查该结果集中的所有 CHILD 部分值以查看这些值是否具有任何 CHILD 部分,然后检查生成的 CHILD 部分对于更多的子部分等,直到没有更多的子部分,然后将那些执行到第一个结果集的内容合并到第一个结果集中,这样它看起来像:
PARENT | CHILD | LEVEL | QTY
-----------------------------
111 | 222 | 0 | 2
222 | 555 | 1 | 1
222 | 777 | 1 | 1
777 | 999 | 2 | 2
222 | 888 | 1 | 1
111 | 333 | 0 | 1
111 | 444 | 0 | 1
查询每深入一步,LEVEL 值都需要递增,最终结果集应显示进入请求的 PARENT 部分的每个部分。
有没有办法在 SQL 中完成所有这些工作?或者我是否必须使用 VB6 或其他程序来迭代循环?感谢任何和所有反馈。
您应该考虑使用自连接,而不是联合。您可以将表与其自身连接起来,从而链接父级和子级 ID。它将需要一个子句来消除与自身连接的行。
child
ID 本质上是示例中的主键,而 parent
ID 充当外键。
这是使用 Microsoft Access 完成此操作的示例,因为它很方便:
表 BMST:
PARENT CHILD LEVEL QTY
111 222 0 2
111 333 0 1
111 444 0 1
222 555 1 1
222 666 1 1
222 777 1 1
555 aaa 2 11
555 aab 2 12
aaa xxx 3 100
aab www 3 111
aaa UUU 3 121
查询:
SELECT c.PARENT, c.CHILD, c.[LEVEL], c.QTY
FROM BMST AS P, BMST AS C
WHERE P.child = C.parent
and P.parent <> C.parent
ORDER BY c.level;
结果:
PARENT CHILD LEVEL QTY
222 777 1 1
222 666 1 1
222 555 1 1
555 aab 2 12
555 aaa 2 11
aaa UUU 3 121
aab www 3 111
aaa xxx 3 100
请注意,我发明了一些附加记录来证明这涵盖了层次结构的所有级别。该查询是不完美的,因为最顶层的父级被排除(本身没有父级),这可能可以通过使用外连接来解决。
奇怪的是,这个特定示例查询的结果非常模仿表本身,但这是在应用任何其他条件之前,例如您真正感兴趣的父元素。
这个问题可以提供更多信息:自连接的解释
要做你想做的事,你需要一种叫做递归的东西。当然,您可以逐行解析它(使用 T-SQL,或使用 VB,或任何您熟悉的语言),但是,这个问题(递归)很容易用称为
Common Table Expressions
或 CTE
的东西解决.
使用
CTE
,您可以结合您的结果,因此在这种情况下,可以解决“子”可以是“父”的“父子”关系。
我创建了这个脚本来向您展示如何操作。首先我填充一些临时表,之后我使用
CTE
进行查询
if object_id('tempdb..#BMST') is not null
begin
drop table #BMST
end
create table #BMST (
PARENT varchar(5)
, CHILD varchar(5)
, LEVEL varchar(5)
, QTY varchar(5)
)
insert into #BMST
select '111', '222', 0, 2
union all select '111', '333', 0, 1
union all select '111', '444', 0, 1
union all select '222', '555', 1, 1
union all select '222', '666', 1, 1
union all select '222', '777', 1, 1
union all select '777', '999', 2, 2
吹就是
CTE
。 Common Table Expression
始终必须是第一个语句,因此使用分号。之后with xxx as ()
施工开始。 results
是一个虚构的名称,可以是任何名称。
(在这个例子中,我使用了一个新的 colom SECONDLEVEL
来向您展示新的级别)
;with results as (
select *
, 0 as SECONDLEVEL
from #BMST b
union all
select b.*
, r.SECONDLEVEL + 1 as SECONDLEVEL
from #BMST b
inner join results r
on r.CHILD = b.PARENT
and b.LEVEL > r.LEVEL
)
select *
from results
如您所见,我正在使用
UNION ALL
运算符。顶部部分正在查询 #temp
表,底部部分则使用该表连接到已获取的结果。
就是这样。你现在有递归了。