【问题标题】:SUM of the SUMs in MS Access SQLMS Access SQL 中 SUM 的总和
【发布时间】:2018-05-27 07:27:17
【问题描述】:

亲爱的,我有一个关于 MS Access SQL 的问题。我有 4 张桌子。

在 Union All 和 SUM 之后,到目前为止,我拥有 SUM 数量的所有 COUNT。现在我需要按行和按列的所有 SUM 的总和。感谢您的帮助。

当前结果:

 ID Name  5/1/2018 5/2/2018 5/3/2018 Count
-- ----- -------- -------- -------- -----
1  Susan       20       30       45     3
2  Juan        15       70              2
3  Tracy       50       60       40     3
4  Jenny       60       8        60     3
5  Bill                         100     1

预期结果:

ID Name  5/1/2018 5/2/2018 5/3/2018 Count E_Total
-- ----- -------- -------- -------- ----- -------
1  Susan       20       30       45     3    95
2  Juan        15       70              2    85
3  Tracy       50       60       40     3   150
4  Jenny       60       8        60     3   128
5  Bill                         100     1   100
D_Total       145       168     245         558

当前查询:

select es.EmpID, es.FirstName, 
   sum(switch(es.DateS = #5/1/2018#, es.Amount)) AS [5/1/2018], 
   sum(switch(es.DateS = #5/2/2018#, es.Amount)) AS [5/2/2018],
   sum(switch(es.DateS = #5/3/2018#, es.Amount)) AS [5/3/2018],
   (max(iif(es.DateS = #5/1/2018#, 1, 0)) +
    max(iif(es.DateS = #5/2/2018#, 1, 0)) +
    max(iif(es.DateS = #5/3/2018#, 1, 0))
   ) as num_dates      
from (
select e.EmpID, e.FirstName, s.DateS, s.Amount 
      from Employee as e inner join
           Sale as s on ( s.EmployeeID = e.EmpID AND s.Amount IS NOT NULL)
      where s.DateS between #5/1/2018# and #5/3/2018#
      union all
      select e1.EmpID, e1.FirstName, s1.DateS, s1.Amount 
      from Employee1 as e1 inner join
           Sale1 as s1 on ( s1.EmployeeID = e1.EmpID and s1.Amount IS NOT NULL)
      where s1.DateS between #5/1/2018# and #5/3/2018#
     ) as es
group by es.EmpID, es.FirstName 
order by es.EmpID;

我有这里的表格和查询。
如图所示,列“E_Total”和行“D_Total”是我需要的样子。或者,我应该停在这里并在 VB.NET 中编写 DataGridView 来完成这项工作吗?非常感谢您的帮助或建议.

【问题讨论】:

  • 请将查询分享为文本,以便我们修改,而不是照片。另外,如果这是家庭作业,请说出来,并阅读How do I ask and answer homework questions?
  • 添加一些背景知识,这是托尼的第二个问题,这是他第一个问题的后续。可以找到here。由于最好的解决方案是特定于 MS Access,因此建议发布一个带有 MS Access 标签的新解决方案。
  • @LukStorms 感谢背景。当我看到照片而没有尝试时,我总是有点担心,因为我不想做别人的功课,打扰他们的学习过程。但我猜他确实自己制作了这些照片(我仍然不知道为什么它们不是屏幕截图),以及为什么他自己没有将代码共享为代码。感谢您在之前的答案中付出的努力。
  • 嗨 Erik 和 LukStorm,这不是作业。这是我自己的业务的 vb.net 项目的一部分。这是我拉我员工的工作来计算他们的佣金的一部分。我在 VB6 中有这个程序的旧版本。现在我想用更好的 SQL 改进到 VB.NET。所以请放心,它不适合学校。感谢您的时间、帮助和关注。我是发布这样的问题的新手,所以我不知道如何发布问题。我看到你可以如此整齐地缩进作品或问题,但我什至无法如此努力。很抱歉。
  • 我 18 年前在大学学习 SQL,我的旧 vb6 程序是 12 岁。我必须每天使用 Select 语句并将它们放入数据网格表中,然后将它们逐天相加。这就是我为什么需要重做程序的原因之一。谢谢 LukStorm 非常好,耐心地帮助我。

标签: sql vb.net ms-access


【解决方案1】:

您实际上是在计算哪些列不为空。因为您是在一行中计数,所以最简单的方法就是使用IIF 语句:

SELECT DISTINCT EmpID, FirstName, 
 Sum(Switch(q.DateS = #5/1/2018#, q.Amount)) AS [5/1/2018], 
 Sum(Switch(q.DateS = #5/2/2018#, q.Amount)) AS [5/2/2018],
 Sum(Switch(q.DateS = #5/3/2018#, q.Amount)) AS [5/3/2018]
 Iif(Sum(Switch(q.DateS = #5/1/2018#, q.Amount)) Is Not Null, 1, 0) +
 Iif(Sum(Switch(q.DateS = #5/2/2018#, q.Amount)) Is Not Null, 1, 0) +
 Iif(Sum(Switch(q.DateS = #5/3/2018#, q.Amount)) Is Not Null, 1, 0) As [Count]
FROM 
( 
    SELECT u1.EmpID, u1.FirstName, a1.DateS, a1.Amount 
    FROM Employee AS u1 
    INNER JOIN Sale AS a1 
       ON (a1.EmployeeID = u1.EmpID AND a1.Amount IS NOT NULL) 
    WHERE a1.DateS BETWEEN #5/1/2018# AND #5/3/2018#

    UNION ALL 

    SELECT u2.EmpID, u2.FirstName, a2.DateS, a2.Amount 
    FROM Employee1 AS u2 
    INNER JOIN Sale1 a2 ON (a2.EmployeeID = u2.EmpID AND a2.Amount IS NOT NULL) 
    WHERE a2.DateS BETWEEN #5/1/2018# AND #5/3/2018#

) AS q 
GROUP BY q.EmpID, q.FirstName 
ORDER BY q.EmpID;

请注意,有时,您可以在使用其他计算列进行计算时引用列名,例如Iif([5/1/2018] Is Not Null。我不知道 Access 中何时允许和不允许的具体情况,所以我倾向于避免它。

【讨论】:

  • 啊,我明白了。好吧,在另一个数据库中,我可能会像count(case when q.Date between ... and ... then q.Amount end) 那样做一些事情。由于对值的计数不计算 NULL。并且不知道该 Switch 函数是否可以返回空值。但乍一看,这应该有效。我曾建议考虑使用 PIVOT,但我猜这些日期列名称可能会比较棘手。
  • 我主要选择这种方法是因为 Access 应该能够将该计数优化为行级计算(它不需要对表中的任何其他内容进行计数或求和,因为所有这些 SUM事情已经计算好了)。如果这些还没有计算出来,我可能会走你的路。很难确切地说优化器在 Access 中的智能程度,因为如果没有奇怪的技巧,我看不到执行计划,但我相信它可以很好地优化这一点。
  • 我的下一个问题是:我可以在当前 SQL 中使用更多 SQL 来按员工和日期对所有 SUM 求和吗?这意味着按行和按列?谢谢
【解决方案2】:

在另一个数据库中,您将使用count(distinct)。这不是 MS Access 中的选项。

我会这样写:

select es.EmpID, es.FirstName, 
   sum(switch(es.DateS = #5/1/2018#, es.Amount)) AS [5/1/2018], 
   sum(switch(es.DateS = #5/2/2018#, es.Amount)) AS [5/2/2018],
   sum(switch(es.DateS = #5/3/2018#, es.Amount)) AS [5/3/2018],
   (max(iif(es.DateS = #5/1/2018#, 1, 0)) +
    max(iif(es.DateS = #5/2/2018#, 1, 0)) +
    max(iif(es.DateS = #5/3/2018#, 1, 0))
   ) as num_dates      
from (
  select e.EmpID, e.FirstName, s.DateS, s.Amount 
  from Employee as e inner join
       Sale as s on (s.EmployeeID = e.EmpID AND s.Amount IS NOT NULL)
  where s.DateS between #5/1/2018# and #5/3/2018#
  union all
  select e1.EmpID, e1.FirstName, s1.DateS, s1.Amount 
  from Employee1 as e1 inner join
       Sale1 as s1 on (s1.EmployeeID = e1.EmpID and s1.Amount IS NOT NULL)
  where s1.DateS between #5/1/2018# and #5/3/2018#
 ) as es
group by es.EmpID, es.FirstName 
order by es.EmpID;

注意事项:

  • select distinct 几乎从不与group by 一起使用。在这种情况下,您当然不需要它。
  • 当您给表格别名时,请使用表格缩写作为别名。它使查询更容易理解。
  • 限定所有列名,而不仅仅是其中的一些。

【讨论】:

  • 您的所有Max 语句都缺少右括号(只有一个需要两个来关闭MaxIif),从而导致语法错误。另外,正如我在评论中的回答所说,重用聚合有时可以让执行运行得更快,因为它可以根据结果集中的其他列进行计算,不需要单独计算。
  • 非常感谢 Gordon 和 Erik,我会试试这个。
猜你喜欢
  • 1970-01-01
  • 2020-04-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多