Sql Server与Aggregate的多个连接

时间:2015-03-11 04:17:55

标签: sql-server left-join aggregate-functions

我试图修复继承代码中的错误。此查询旨在带回amex_meal_amount_total of $33,但它正在提供$99。问题在于第二次加入 - 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  

我很清楚开发人员试图在连接中使用表别名(例如EE_AMEX)来将sum函数限制为连接中的条件。

EE table的{​​{1}}只有一行line_item_type_id 1。当我删除其他连接语句时,它会带回预期的ID

$33

是否有直接的解决方法,或者我是否需要完全重构查询?

表格结构:

试图让这个问题变得简单

expense_report:
report_id(PK)

expense_expense
report_id(FK,一对多)
meal_amount(可以是每行report_id的多行膳食量)
taxi_amount(其他费用的例子)
line_item_type_id(1是AMEX,2是OOP,每行可以是任何一个)

在这种情况下,ER在expense_expense中有一个相关的行,用餐费为33美元,这就是我所期望的。

然而,其他收费有三个相关行,例如出租车等。

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

感谢。

2 个答案:

答案 0 :(得分:1)

如何将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  

答案 1 :(得分:1)

如果您正在寻找为什么第一个查询返回99美元,让我们看看如何。 将表定义为

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;

因此,在第一次离开与费用表的连接后,结果将是单行

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

注意列。第一个表的meal_amount重复,因为它正在连接右表的2行。 因此,对此进行总结将导致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