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

时间:2017-04-21 03:52:03

标签: sql sql-server sql-server-2008 tsql vb6

所以我想说我有一张桌子,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

该表提供了用于制作PARENT部件的所有CHILD部件的信息,以及每个PARENT部件中使用的QUILD OF CHILD部件。 LEVEL列的值为'0',因为部分'111'是我们关心的原点部分。我们不关心部分'111'是另一个较大的PARENT部分的CHILD部分。

如果CHILD部件由较小的CHILD部件组成,它们也可能是PARENT部件。例如,此查询:

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部分的CHILD部分。

更进一步,部分'222'的CHILD部分本身可能有CHILD部分,因此对'777'部分的类似查询将返回:

PARENT | CHILD  | LEVEL | QTY 
-----------------------------
777    | 999    | 2     | 2   

我的问题是,是否可以创建一个返回第一个结果集的查询,然后检查该结果集中的所有CHILD部分值,看看它们是否有任何CHILD部分,然后检查结果更多CHILD部件等的CHILD部件,直到没有更多CHILD部件,然后UNION那些进入第一个结果集的部件,如下所示:

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或其他程序来遍历循环?感谢任何反馈。

2 个答案:

答案 0 :(得分:2)

您应该查看SELF JOIN而不是联合。您可以将表连接到自身,从而链接父和子。儿童身份证。它将需要一个子句来消除与自己连接的行。 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

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

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

此问题可提供更多信息:Explanation of self-joins

答案 1 :(得分:1)

要做你想做的事,你需要一些叫做递归的东西。当然,你可以逐行解析它(使用T-SQL,或使用VB,或者你熟悉的任何语言),但是,这个问题(递归)很容易通过名为Common Table Expressions或{的东西来解决。 {1}}。

使用CTE你可以结合你的结果,所以在这种情况下,孩子可以成为父母的父母与孩子的关系。

我已创建此脚本以向您展示如何操作。首先我填充一些临时表,之后我使用CTE

进行查询
CTE

Blow是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 ()是一个虚构的名字,可以是任何东西。 (在此示例中,我使用新的colom results向您显示新级别)

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表,它使用它来加入已经提取的结果的底部。

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