是否可以使用结果中的值将另一个结果合并到前一个结果集中?

问题描述 投票:0回答:2

假设我有一张桌子,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 或其他程序来迭代循环?感谢任何和所有反馈。

sql sql-server sql-server-2008 t-sql vb6
2个回答
3
投票

您应该考虑使用自连接,而不是联合。您可以将表与其自身连接起来,从而链接父级和子级 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

请注意,我发明了一些附加记录来证明这涵盖了层次结构的所有级别。该查询是不完美的,因为最顶层的父级被排除(本身没有父级),这可能可以通过使用外连接来解决。

奇怪的是,这个特定示例查询的结果非常模仿表本身,但这是在应用任何其他条件之前,例如您真正感兴趣的父元素。

这个问题可以提供更多信息:自连接的解释


1
投票

要做你想做的事,你需要一种叫做递归的东西。当然,您可以逐行解析它(使用 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
表,底部部分则使用该表连接到已获取的结果。

就是这样。你现在有递归了。

© www.soinside.com 2019 - 2024. All rights reserved.