2014-09-29 56 views
1

我有以下三个表格表示树结构。 #A中的每一行都是#B中零行或更多行的祖先。同样,#B中的每一行都是#C中零行或更多行的祖先。表#B包含一列value。我需要为属于输入祖先的#B中的所有行找到value的总和。总结查询结果的不同元素

例如,考虑表的内容如下:

CREATE TABLE #A (id varchar(10)); 
CREATE TABLE #B (id varchar(10), value int); 
CREATE TABLE #C (id varchar(10), a_id varchar(10), b_id varchar(10)); 

INSERT INTO #A(id) VALUES ('A1'), ('A2'); 
INSERT INTO #B(id, value) VALUES('B1', 41), ('B2', 43), ('B3', 47); 
INSERT INTO #C(id, a_id, b_id) VALUES('C1', 'A1', 'B1'), ('C2', 'A1', 'B1'), 
            ('C3', 'A1', 'B2'), ('C4', 'A2', 'B3'); 

以上内容表示如下结构:

A1 
|--- B1 (41) 
| |-------- C1 
| |-------- C2 
| 
|--- B2 (43) 
    |-------- C3 
A2 
|--- B3 (47) 
    |-------- C4 

的父 - 子关系被古怪定义。表#B没有自己的列表,表#A中的哪一行是它的祖先。所有映射都应根据表#C进行评估。列表a_idb_id分别在表#C中指定祖父母行和父行分别在表#A#B中。如果有一排Z#C其中a_idXb_idY,然后XYY祖先是Z祖先。在#C中不会有冲突的映射。

问题陈述:对于给定的ID A1,发现value列的所有行中#B,其父母为A1的总和。这里有两个孩子A1,B1其值为41B2的值为43所以我们期望答案是84

如果我这样做如下:

SELECT SUM(#B.value) FROM #B 
INNER JOIN #C ON #B.id = #C.b_id 
INNER JOIN #A ON #C.a_id = #A.id 
WHERE #A.id = 'A1' 

我得到12541 + 41 + 43代替84,因为在#A两行具有映射B1 -> C1。我可以写下面的查询来获取与#B中的不同行相关联的值,即4143,但是现在我不知道如何对结果值进行求和。我能否在不创建临时表的情况下获得预期结果?

SELECT MAX(#B.value) FROM #B 
INNER JOIN #C ON #B.id = #C.b_id 
INNER JOIN #A ON #C.a_id = #A.id 
WHERE #A.id = 'A1' 
GROUP BY #B.id; 

我不是SQL专家,所以可能会有一个非常简单的解决方案。

回答

1

你不这里需要表#A,因为这些ID在表#C中,表中的值在表#B中。这就是你所需要的。无需加入。只需从#C中选择所需的ID,然后使用它们从#B中选择。

select sum(value) 
from #B 
where id in 
(
    select b_id 
    from #C 
    where a_id = 'A1' 
); 
+0

这是最简单的解决方案。正如你所说的,表格#A不是必需的。还有一点要记住:当我们需要删除重复项时,INNER JOIN'不能替代WHERE-IN子句。 – 2014-09-29 13:55:51

1

你可以这样做:

SELECT SUM(#B.value) 
FROM #B 
WHERE EXISTS 
(
    SELECT NULL FROM #C 
    INNER JOIN #A ON #C.a_id = #A.id 
    WHERE #B.id = #C.b_id 
    AND #A.id = 'A1' 
) 

然后在那里的其他表中存在,你将只能总结#B

结果将是:84

0

稍有不同的方法。

SELECT SUM(#B.value) FROM #B 
INNER JOIN (
    SELECT DISTINCT a_id, b_id FROM #C 
) temp 
ON 
temp.b_id=#B.ID 
WHERE temp.a_id='A1'; 

这样做的好处是可以改变WHERE temp.a_id='A1'GROUP BY temp.a