我有两张桌子(这些是第三方应用程序的一部分,因此我无法更改其架构):
node.doc_id是指doc.doc_id值(没有外键关系),node.parent_node_id是指node.node_id值,设置doc表中值的父/子关系。 doc表中的每个条目都可以有零个或一个父级,以及任意数量的子级。
对于给定的部件号,我需要doc表中所有匹配条目的名称和描述AND(这里是棘手的部分)每个这样的匹配条目我需要知道该条目是否有任何活动的子项
以下是一个例子:
doc
doc_id is_active part_number name description
1 T AAA Fred Little
2 T AAA George Middle
3 T AAA Sam Morse
4 T CCC Mary Moo
5 T DDD Carol Smith
6 F DDD Midge Moo
node
node_id doc_id parent_node_id
10 1 null
11 2 null
12 3 null
13 4 10
14 5 10
15 6 11
因此,您可以看到doc_id 1有2个子节点(doc_ids 4和5),doc_id 2有一个子节点(doc_id 6)。
图形:
doc [doc_id = 1] - >节点[DOC_ID = 1,NODE_ID = 10]; parent_node_id = 10的节点是节点[node_id = 13,doc_id = 4]和节点[node_id = 14,doc_id = 5]; doc [doc_id = 4]和doc [doc_id = 5]都有is_active = T.
doc [doc_id = 2] - >节点[DOC_ID = 2,NODE_ID = 11]; parent_node_id = 11的唯一节点是node [node_id = 15,doc_id = 6],但doc [doc_id = 6]的is_active = F.
如果我要求part_number = AAA,我需要回来:
doc_id name description has_active_children
1 Fred Little T
2 George Middle F
3 Sam Morse F
现在我已经得到了这个查询,我计算了孩子的数量(这是不必要的,但我唯一可以弄明白的):
select d1.*,
(select count(dn.node_id) from node dn
inner join doc dc on dn.doc_id=dc.doc_id
where dn.parent_node_id=
(select dx.node_id from node dx where dx.doc_id=d1.doc_id)
and dc.is_active='T') as childCount
from doc d1 where d1.part_number='AAA'
这种方法有效,但速度非常快。我们在SQL Server上运行,我尝试了"设置showplan_all"但是没有充分理解输出,无法做出任何改变。
有没有明显更好的方法来执行此查询?或者,是否有一个文档可以帮助我理解showplan输出?
答案 0 :(得分:1)
这应该是一个不错的起点。我必须在数据库中进行类似的自连接,该数据库具有地理区域的层次表示。
如果您将2个left join
语句中的任何一个更改为简单的join
,那么任何没有孩子的父母都将从查询结果中删除。
SELECT parent.[doc_id],
parent.[name],
parent.[description],
parent.[part_number],
CASE WHEN COUNT(child.[doc_id]) > 0 THEN 'T' ELSE 'F' END
FROM doc parent
JOIN node parentRef on parent.[doc_id] = parentRef.[doc_id]
LEFT JOIN node childRef on parentRef.[node_id] = childRef.[parent_node_id]
LEFT JOIN doc child on child.[doc_id] = childRef.[doc_id]
WHERE parent.[part_number] = 'AAA'
GROUP BY parent.[doc_id], parent.[name], parent.[part_number], parent.[description]
编辑: 将part_number添加到查询
此外,与任何SQL查询一样,请查看这些表中存在的索引。您可以添加一个或两个索引来提高查询性能。
答案 1 :(得分:0)
您可以使用适合您案例的窗口功能。
SELECT parent.[doc_id],
parent.[name],
parent.[description],
parent.[part_number],
CASE WHEN ROW_NUMBER(PARTITION BY child.[doc_id]) > 0 THEN 'T' ELSE 'F' END AS childCount
FROM doc parent
JOIN node parentRef on parent.[doc_id] = parentRef.[doc_id]
LEFT JOIN node childRef on parentRef.[node_id] = childRef.[parent_node_id]
LEFT JOIN doc child on child.[doc_id] = childRef.[doc_id]
WHERE parent.[part_number] = 'AAA' AND child.is_active = 'T'