【问题标题】:SQL SELECT Sum values without including duplicatesSQL SELECT Sum 值不包括重复项
【发布时间】:2015-10-04 07:07:50
【问题描述】:

我正在努力解决 Oracle SQL 中的一个问题。

我将举例说明。我要查询三个表:

Employees
__________________________________________
| EmployeeID | Name                      |
| 1          | John Smith                |
| 2          | Douglas Hoppalot          |
| 3          | Harry Holiday             |
... 



InternalCosts
________________________________
| IntID | Amount | EmployeeID  |
| 1     | 10     |     1       |
| 2     | 20     |     2       |
| 3     | 30     |     1       |
...


ExternalCosts
________________________________
| ExtID | Amount | EmployeeID  |
| 1     | 40     |     1       |
| 2     | 50     |     2       |
| 3     | 60     |     1       |
...

我想要实现的是每个员工一行的结果,以及他们每个内部和外部成本的总和,即

____________________________________________________________
| Name             | InternalCostTotal | ExternalCostTotal |
| John Smith       | 40                | 100               |
| Douglas Hoppalot | 20                | 50                |
...

我遇到的问题是,当我同时查询 InternalCosts 和 ExternalCosts 表时,我得到了每个成本排列,而不仅仅是每个员工一个。当我按员工姓名分组并对金额字段求和时,值太高了。我尝试过的:

SELECT emp.Name, sum(int.Amount), sum(ext.Amount) 
FROM Employees emp,
     InternalCosts int,
     ExternalCosts ext
WHERE emp.EmployeeId = int.EmployeeID
  and emp.EmployeeID = ext.EmployeeID
GROUP BY emp.Name

上面的例子会返回:

 ____________________________________________________________
 | Name             | InternalCostTotal | ExternalCostTotal |
 | John Smith       | 80                | 200               | <- too high!
 | Douglas Hoppalot | 20                | 50                |
 ...

感谢任何帮助/建议/想法!

【问题讨论】:

  • 问题是当你用 internalcosts 连接员工时,当employeeid =1 时你会得到两行,当你用 externalcosts 连接结果的 2 行时,它将返回 4 行,然后计算总和。将 int.extid=int.intid 放在 where 子句中。

标签: sql oracle select group-by sum


【解决方案1】:

您应该在 int 和 ext 上使用子查询进行求和,并加入子查询。

我还建议使用显式 JOIN,而不是表、表、表

例如

SELECT emp.Name, int.Amount AS InternalCostTotal, ext.Amount AS ExternalCostTotal
FROM Employees emp
JOIN ( 
    SELECT EmployeeID, SUM(Amount) AS Amount 
    FROM InternalCosts 
    GROUP BY EmployeeID 
) int ON emp.EmployeeId = int.EmployeeID
JOIN ( 
    SELECT EmployeeID, SUM(Amount) AS Amount 
    FROM ExternalCosts 
    GROUP BY EmployeeID 
) ext ON emp.EmployeeId = ext.EmployeeID

【讨论】:

    【解决方案2】:

    SQL Fiddle

    Oracle 11g R2 架构设置

    CREATE TABLE Employees ( EmployeeID, Name ) AS
              SELECT 1, 'John Smith' FROM DUAL
    UNION ALL SELECT 2, 'Douglas Hoppalot' FROM DUAL
    UNION ALL SELECT 3, 'Harry Holiday' FROM DUAL;
    
    CREATE TABLE InternalCosts ( IntID, Amount, EmployeeID ) AS
              SELECT 1, 10, 1 FROM DUAL
    UNION ALL SELECT 2, 20, 2 FROM DUAL
    UNION ALL SELECT 3, 30, 1 FROM DUAL;
    
    CREATE TABLE ExternalCosts ( ExtID, Amount, EmployeeID ) AS
              SELECT 1, 40, 1 FROM DUAL
    UNION ALL SELECT 2, 50, 2 FROM DUAL
    UNION ALL SELECT 3, 60, 1 FROM DUAL;
    

    查询 1

    SELECT e.*,
           ( SELECT SUM( Amount ) FROM InternalCosts i WHERE e.EmployeeID = i.EmployeeID ) AS InternalCostTotal,
           ( SELECT SUM( Amount ) FROM ExternalCosts x WHERE e.EmployeeID = x.EmployeeID ) AS ExternalCostTotal
    FROM   Employees e
    

    Results

    | EMPLOYEEID |             NAME | INTERNALCOSTTOTAL | EXTERNALCOSTTOTAL |
    |------------|------------------|-------------------|-------------------|
    |          1 |       John Smith |                40 |               100 |
    |          2 | Douglas Hoppalot |                20 |                50 |
    |          3 |    Harry Holiday |            (null) |            (null) |
    

    或者(使用连接):

    WITH InternalTotals AS (
      SELECT EmployeeID,
             SUM( Amount ) AS InternalCostTotal
      FROM   InternalCosts
      GROUP BY
             EmployeeID
    ),
    ExternalTotals AS (
      SELECT EmployeeID,
             SUM( Amount ) AS ExternalCostTotal
      FROM   ExternalCosts
      GROUP BY
             EmployeeID
    )
    SELECT e.EmployeeID,
           i.InternalCostTotal,
           x.ExternalCostTotal
    FROM   Employees e
           LEFT OUTER JOIN
           InternalTotals i
           ON ( e.EmployeeID = i.EmployeeID )
           LEFT OUTER JOIN
           ExternalTotals x
           ON ( e.EmployeeID = x.EmployeeID );
    

    【讨论】:

      【解决方案3】:

      这应该可以解决问题:

      SELECT emp.Name, NVL(IntAmount,0), NVL(ExtAmount,0)
      FROM Employees emp
        LEFT JOIN
          (SELECT EmployeeID, sum(Amount) as IntAmount
           FROM InternalCosts GROUP BY EmployeeID) int
          ON emp.EmployeeID = int.EmployeeID
        LEFT JOIN
          (SELECT EmployeeID, sum(Amount) as ExtAmount
           FROM ExternalCosts GROUP BY EmployeeID) ext
          ON emp.EmployeeID = ext.EmployeeID
      

      还请注意,在这种情况下以及将来可能对您的表结构进行规范化可能会对您有所帮助(我的意思是将外部成本和内部成本合并到一个表中,前提是当然可以)。

      【讨论】:

      • 谢谢!不幸的是,我正在处理的查询比我的示例中的要复杂得多,并且是在 PowerBuilder 应用程序中动态构建的,因此在这种情况下我不想使用连接。通常我总是尝试使用连接,但我更喜欢它。
      【解决方案4】:

      我建议您改为使用 Employee ID 尝试一个组,然后再进行 INNER 联接以投影 Employee 表中的名称。

      干杯!

      【讨论】:

      • 如何根据您的建议添加查询以支持您的答案?它会让您更清楚地了解您要说的内容。
      • 谢谢,我从其他答案之一中得到了解决方案,但非常感谢您回答我的问题!
      【解决方案5】:

      试试这个

      SELECT t1.emp_name,inernalAmount,sum(ext.Amount) as externalAmount from
      (
      SELECT emp.EmployeeID,emp.Name, sum(int.Amount) as internalAmount 
      FROM Employees emp inner join InternalCosts int on emp.EmployeeId = int.EmployeeID
      ) t1 inner join ExternalCosts ext on t1.EmployeeID = ext.EmployeeID
      GROUP BY t1.Name,internalAmount
      

      【讨论】:

      • 您的查询无法正常工作。您的子查询中缺少 group by,加上 t1.emp_name 不存在(t1.name?),并且您在外部选择的列列表中拼错了“internalamount”。
      • 谢谢,我为我的其他问题之一找到了解决方案,但很高兴你能回答我的问题。
      猜你喜欢
      • 2014-08-23
      • 2015-10-06
      • 1970-01-01
      • 2013-03-31
      • 1970-01-01
      • 1970-01-01
      • 2015-11-10
      • 2017-03-17
      • 1970-01-01
      相关资源
      最近更新 更多