【问题标题】:How to SUM and Subtract from different table columns in MSACCESS如何从 MS ACCESS 中的不同表列中求和和减去
【发布时间】:2012-12-09 10:05:26
【问题描述】:

我有三个名为:Student、StudentPayment 和 CreditAmount 的表。我想显示一个学生欠学校多少钱的结果。在学生表中有一个名为 TotalPayable 的列,它是要支付给学校的总金额,在 StudentPayment 中有一个名为 TotalPaid 的列,它是他每次支付的总金额,在 CreditAmount 表中有一个名为 CreditAmount 的列是学校给予学生的豁免金额。所以我做了一个查询:

SELECT Student.TotalPayableAmount - 
       Sum(StudentPayment.TotalPaid, CreditAmount.WaiverAmount) AS Total_Due
  FROM (Student INNER JOIN StudentPayment ON Student.ID = StudentPayment.ID) 
 INNER JOIN CreditAmount ON (Student.ID = CreditAmount.ID) AND (Student.ID = CreditAmount.StudentID)
 GROUP BY Student.ID, Student.TotalPayableAmount, CreditAmount.WaiverAmount 

但它显示错误。

实际上,我想计算 TotalPaid 和 CreditAmount 的总和,然后想从学生表的 TotalPayable 中减去它。任何人都可以帮我解决这个问题。提前致谢。

【问题讨论】:

    标签: sql database ms-access


    【解决方案1】:

    join 对右侧的每一行重复左侧的每一行。所以一个有两次付款和三个学分的学生最终会得到 6 行。如果你 sum 超过这个,你会得到错误的结果。

    相反,您可以使用子查询来计算每个学生的总金额。由于每个学生的子查询只返回一行,因此可以避免上面提到的行重复问题。例如;

    select  Student.ID
    ,       Student.TotalPayableAmount - 
            iif(StudentPayment.TotalPaid is null, 0, StudentPayment.TotalPaid) -
            iif(CreditAmount.WaiverAmount is null, 0, CreditAmount.WaiverAmount)
    from    (
            Student
            left join    
                    (
                    select  StudentID
                    ,       sum(Paid) as TotalPaid
                    from    StudentPayment
                    group by
                            StudentID
                    ) as StudentPayment
            on    StudentPayment.StudentID = Student.ID
            )
    left join    
            (
            select  StudentID
            ,       sum(Waiver) as WaiverAmount
            from    CreditAmount
            group by
                    StudentID
            ) as CreditAmount
    on      CreditAmount.StudentID = Student.ID
    

    【讨论】:

    • Access 中没有 ISNULL 函数需要一个额外的参数来返回 null 值。请改用Nz,或者如果Nz 不可用,请使用Iif(IsNull(StudentPayment.TotalPaid), 0, StudentPayment.TotalPaid)
    • 此外,如果任何学生在其中一个子查询中没有相应的总数,则该学生将不会出现在结果查询中。使用LEFT JOIN 而不是INNER JOIN
    • @ZevSpitz:好点,更新了答案。我错过了 MS-Access 部分(仅在标题中)
    • Access 与 SQL Server IsNull() 的混淆让我想知道为什么要在这里打扰 IsNull()?不需要:iif(StudentPayment.TotalPaid Is Null, 0, StudentPayment.TotalPaid)
    • @ZevSpitz 过去我看到有人声称Is Null 应该更快,因为数据库引擎不必使用附加功能。但是,我从未测试过,因此不会声称性能优势足够大,甚至根本没有任何优势。 OTOH,我无法想象Is Null 会比函数。所以,对我来说,这个决定是基于:IsNull() 不需要并且没有任何好处,所以不要在这里使用它。
    【解决方案2】:

    您需要单独获取每个表的总和,然后通过学生 ID 将它们连接起来。

    SELECT Student.TotalPayableAmount - Nz(sumTotalPaid,0) - Nz(sumCreditAmount,0)
    FROM (Student
    LEFT JOIN (
        SELECT ID, Sum(TotalPaid) AS sumTotalPaid
        FROM StudentPayment
        GROUP BY StudentPayment.ID
    ) AS sum1
        ON Student.ID = sum1.ID)
    LEFT JOIN (
        SELECT ID, Sum(CreditAmount) AS sumCreditAmount
        FROM CreditAmount
        GROUP BY CreditAmount.ID
    ) AS sum2
        ON Student.ID = sum2.ID
    

    注意:如果您从外部连接(DAO、ADO、ADO.NET)执行此操作,您将无法使用 Nz 函数。

    【讨论】:

    • 是的,我正在使用 ADO.NET Access 数据源。那我应该用什么来代替新西兰呢?
    • Iif(IsNull(sum1.ID), 0, sum1.ID)Iif(IsNull(sum2.ID), 0, sum2.ID)
    • Nz(sum1.ID) 应该是Nz(sum1.TheSum),并且TheSum 应该作为别名添加到子查询中
    • @Andomar 已在帖子中修复,谢谢。 @barsan - 我之前的评论是错误的。使用这个:Iif(IsNull(sumTotalPaid), 0, sumTotalPaid)Iif(IsNull(sumCreditAmount), 0, sumCreditAmount)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-24
    • 2018-06-05
    • 1970-01-01
    • 1970-01-01
    • 2022-08-10
    • 1970-01-01
    相关资源
    最近更新 更多