我有3个表,一个父项和两个孩子,我正在尝试构建一个查询,该查询聚合来自所有3个字段的字段,并通过完全依赖于父表的表达式进行过滤。为了帮助理解这些表格,第二个孩子在第一个孩子和父母中有一个外键;第一个孩子在父母中有一个外键。例如,
parentTable | child1Table | child2Table
-------------+-------------+-------------
id* | id* | id
... | subId* | subId
... | ... | uniqueId*
*
显示构成主键的内容。
我看到两种方法:
SELECT allAggregates
FROM (
SELECT exprOnParentFields, parentAggregates
FROM parentTable
WHERE conditionOnParentRecord GROUP BY exprOnParentFields
) full_p
LEFT JOIN (
SELECT p.exprOnParentFields, c1.child1Aggregates
FROM child1Table c1 LEFT JOIN parentTable p ON c1.id = p.id
WHERE p.conditionOnParentRecord GROUP BY p.exprOnParentFields
) full_c1 ON full_p.exprOnParentFields = full_c1.exprOnParentFields
LEFT JOIN (
SELECT p.exprOnParentFields, c2.child2Aggregates
FROM child2Table c2 LEFT JOIN parentTable p ON c2.id = p.id
WHERE p.conditionOnParentRecord GROUP BY p.exprOnParentFields
) full_c2 ON full_p.exprOnParentFields = full_c2.exprOnParentFields
请注意exprOnParentFields
在任何地方都是一样的,conditionOnParentRecord
也是如此。此外,如果重要,则两者都不一定简单(即只有一个列名)。由于这两件事的重复,我不喜欢这种方法。
备用版本:
CREATE TEMPORARY TABLE filteredIds AS (
SELECT id, exprOnParentFields AS groupExpr
FROM parentTable WHERE conditionOnParentRecord);
SELECT allAggregates
FROM (
SELECT f.groupExpr, p.parentAggregates
FROM parentTable p INNER JOIN filteredIds f ON p.id = f.id
GROUP BY f.exprOnParentFields
) full_p
LEFT JOIN (
SELECT f.groupExpr, c1.child1Aggregates
FROM child1Table c1 INNER JOIN filteredIds f ON c1.id = f.id
GROUP BY f.groupExpr
) full_c1 ON full_p.groupExpr = full_c1.groupExpr
LEFT JOIN (
SELECT f.groupExpr, c2.childAggregates
FROM child2Table c2 INNER JOIN filteredIds f ON c2.id = f.id
GROUP BY f.groupExpr
) full_c2 ON full_p.groupExpr = full_c2.groupExpr
这样可以节省每个联接的完整exprOnParentFields
(现在它只是字段名groupExpr
),并消除了conditionOnParentRecord
的重复。然而,以创造临时性为代价,它并没有像我希望的那样消除。我的[多部分]问题是:
从风格角度来看,这些是首选之一吗?从速度的角度来看? 或者甚至更好,有没有一种不同的更好的方法来做到这一点?
需要注意的重要一点是,由于重复行的聚合,我无法进行单个3部分连接。
答案 0 :(得分:1)
简短的回答是“否”。一般来说,我不知道形成查询的更简单或更有效的方法。如果您要加入的每个表都依赖于“之前”的所有表,那么您几乎必须按照您的说法使用SQL。
根据数据更改的频率以及答案的实时接近程度,您可以构建预先汇总在{{1}上的数据的临时副本表达式,以便您可以使用一个计算的结果加入预先聚合的值(即许多查询)。
当然,为了比较这个(和任何东西)的优缺点,你应该总是使用执行计划和跟踪来告诉你db正在做多少工作。
祝你好运!