【问题标题】:Sql Server Multiple Joins with Aggregate使用聚合的 Sql Server 多个联接
【发布时间】:2015-03-11 04:17:55
【问题描述】:

我正在尝试修复继承代码中的错误。此查询旨在带回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 中只有一行 line_item_type_id 1 用于此 ID。当我删除另一个 join 语句时,它会带回预期的 $33

 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  

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

表结构:

尽量让这个问题保持简单

费用报告:
report_id (PK)

expense_expense
report_id(FK,一对多)
餐量(可以是多行,每个报告 ID 的餐量)
Taxi_amount(其他费用示例)
line_item_type_id(1是AMEX,2是OOP,每行可以任意)

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

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

在运行查询时,它会为三行求和,因此是意外的 99 美元。

谢谢。

【问题讨论】:

  • 为什么在没有使用该表的情况下加入 oop?
  • 第一个查询中的左连接类似于 ER.report_id = EE_AMEX.report_id AND (EE_OOP.line_item_type_id = 1 OR EE_OOP.line_item_type_id = 2)。你在第二个查询中得到了结果。
  • @Giorgi Nakeuri,出于示例目的,我没有包含完整的查询,它也从 EE_OOP 检索聚合。谢谢
  • 能否提供表结构、当前结果集和预期结果集(不是99和33,而是结果应该是什么样子)?
  • 表结构和更多添加。谢谢。

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


【解决方案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  

【讨论】:

    【解决方案2】:

    如果您正在寻找第一个查询返回 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
    

    【讨论】:

      猜你喜欢
      • 2010-11-17
      • 2020-11-17
      • 1970-01-01
      • 2016-06-10
      • 2015-05-30
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 2017-04-19
      相关资源
      最近更新 更多