Sql 服务器多次加入聚合

Sql Server Multiple Joins with Aggregate

我正在尝试修复继承代码中的错误。此查询旨在返回 amex_meal_amount_total of ,但它给出了 </code>。问题出在第二个连接上 - <code>EE table 中有三个关联项使聚合总计三行。

SELECT ER.report_id,
       Isnull(Sum(EE_AMEX.meal_amount), 0) AS amex_meal_amount_total
FROM   expense_report ER (nolock)
       LEFT OUTER JOIN expense_expense EE_AMEX (nolock)
                    ON ER.report_id = EE_AMEX.report_id
                       AND EE_AMEX.line_item_type_id = 1
       LEFT OUTER JOIN expense_expense EE_OOP (nolock)
                    ON ER.report_id = EE_OOP.report_id
                       AND EE_OOP.line_item_type_id = 2
WHERE  er.report_id = 9733
GROUP  BY ER.report_id  

我很清楚开发人员试图在连接中使用 table 别名(例如 EE_AMEX)以将 sum 函数限制为加入。

EE table 中只有一行与此 IDline_item_type_id 1。当我删除其他连接语句时,它会带回预期的 </code>.</p> <pre><code> SELECT ER.report_id, Isnull(Sum(EE_AMEX.meal_amount), 0) AS amex_meal_amount_total FROM expense_report ER (nolock) LEFT OUTER JOIN expense_expense EE_AMEX (nolock) ON ER.report_id = EE_AMEX.report_id AND ee_oop.line_item_type_id = 1 WHERE er.report_id = 9733 GROUP BY ER.report_id

是否有直接的修复方法,或者我是否需要完全重组查询?

Table结构:

尽量让这个问题简单化

expense_report:
report_id(PK)

expense_expense:
report_id(FK,一对多)
meal_amount(可以是多行,每行 report_id)
taxi_amount(其他费用示例)
line_item_type_id(1 是 AMEX,2 是 OOP,每行可以任意)

在这种情况下,急诊室在 expense_expense 中有一个关联行,餐费为 33 美元,这正是我所期望的。

但是,其他费用(例如出租车等)有 3 个关联行。

当 运行 查询时,它会将其汇总为三行,因此意外的 $99。

谢谢。

如何将 sum 改为 subquery?您可能需要为您的 EE_OOP aggregate 做同样的事情,但我不确定您从中得到了什么。

 SELECT ER.report_id,
       Isnull((SELECT Sum(meal_amount)
               FROM   expense_expense EE_AMEX (nolock)
               WHERE  EE_AMEX.report_id = ER.report_id
                      AND EE_AMEX.line_item_type_id = 1), 0) AS
       amex_meal_amount_total
FROM   expense_report ER (nolock)
       LEFT OUTER JOIN expense_expense EE_OOP (nolock)
                    ON ER.report_id = EE_OOP.report_id
                       AND EE_OOP.line_item_type_id = 2
WHERE  er.report_id = 9733  

如果您正在寻找第一个查询返回 99 美元的原因,让我们看看如何。 让 tables 定义为

select 1 report_id into #expense_report;

select * into #expense_expense from (
select 1 report_id, 33 meal_amount, 0 taxi_amount, 1 line_item_type_id
union all
select 1 report_id, 0 meal_amount, 33 taxi_amount, 2 line_item_type_id
union all
select 1 report_id, 0 meal_amount, 33 taxi_amount, 2 line_item_type_id) t;

所以在第一个 left join with expense table 之后结果将是一行

SELECT *
FROM   #expense_report ER (nolock)
       LEFT OUTER JOIN #expense_expense EE_AMEX (nolock)
                    ON ER.report_id = EE_AMEX.report_id
                       AND EE_AMEX.line_item_type_id = 1
WHERE  er.report_id = 1;

report_id   report_id   meal_amount taxi_amount line_item_type_id
1               1         33            0             1

现在第二个左连接将应用于此结果,即单行连接到双行结果,这将产生 2 行。

SELECT *
FROM   #expense_report ER (nolock)
       LEFT OUTER JOIN #expense_expense EE_AMEX (nolock)
                    ON ER.report_id = EE_AMEX.report_id
                       AND EE_AMEX.line_item_type_id = 1
       LEFT OUTER JOIN #expense_expense EE_OOP (nolock)
                    ON ER.report_id = EE_OOP.report_id
                       AND EE_OOP.line_item_type_id = 2
WHERE  er.report_id = 1;

report_id   report_id   meal_amount taxi_amount line_item_type_id   report_id   meal_amount taxi_amount line_item_type_id
1   1   33  0   1   1   0   33  2
1   1   33  0   1   1   0   33  2

记下这些列。第一个 table 的 meal_amount 重复,因为它与右侧的 2 行 table 连接。 因此,对其求和将得到 66 美元而不是 33 美元。

如果您想在单行但不同的列中同时显示出租车和餐费,请使用以下查询:

SELECT ER.report_id,
       Isnull(Sum(case when EE_AMEX.line_item_type_id  =1 then EE_AMEX.meal_amount end), 0) AS amex_meal_amount_total,
       Isnull(Sum(case when EE_AMEX.line_item_type_id  =2 then EE_AMEX.taxi_amount end), 0) AS amex_taxi_amount_total
FROM   #expense_report ER (nolock)
       LEFT OUTER JOIN #expense_expense EE_AMEX (nolock)
                    ON ER.report_id = EE_AMEX.report_id
WHERE  er.report_id = 1
GROUP  BY ER.report_id