【问题标题】:SQL query within SQL query on sumSQL 查询中的 SQL 查询总和
【发布时间】:2016-10-24 20:32:02
【问题描述】:

我有两张表,Employees 和 EmployeeVacations。我正在尝试执行 SQL 查询,以获取每个员工已休的休假时间以及截至今天的当前余额的总和。这是我当前的 SQL 查询:

SELECT
    e.PIN,
    e.FirstName,
    e.LastName,
    e.Uniform,
    e.AL_Cap,
    ev.Value AS '10/1 Balance',
    (SELECT
        SUM(value)
    FROM EmployeeVacations
    WHERE CreationDate >= '2016-10-01'
    AND Vacation_Type = 'Taken'
    AND Vacation_Kind = 'AL'
    AND EmployeeId = 13)
    AS Taken
FROM    employees e,
        EmployeeVacations ev
WHERE e.Id = ev.EmployeeId
AND ev.IsHistory = 0
AND ev.Vacation_Type = 'Forward'
AND ev.Vacation_Kind = 'AL'
AND EmployeeId = 13
ORDER BY e.LastName, e.FirstName

如果我选择一个员工,这很有效。如果我删除“其中 EmployeeId = 13”,我会得到所有员工的列表,其中包含每行中每个人的总假期总和(如 1,300 小时)。我如何分解它以便只显示每个员工的 Taken?

【问题讨论】:

  • 根据您使用的 sql server 版本,这可能会使用窗口函数来处理。
  • 你应该使用显式连接——它更清晰。
  • 您正在显示员工的转发记录列表,每条记录以及员工的总和。这是想要的吗?还是您也想要员工的预付款,即每位员工只有一个结果行?

标签: sql sql-server tsql


【解决方案1】:

您需要一个相关查询,其中子查询使用“父”查询中的值。

SELECT e.PIN ...
    (select SUM(value) .... WHERE EmployeeID = e.id) as taken
                                               ^^^^^

请注意,这些可能非常低效,因为内部查询必须为父查询的每一行执行一次。在很多情况下,您最好将其重写为具有适当分组的常规 JOIN 查询。

【讨论】:

  • 强调 Mac 的最后一段。 99% 的机会可以更有效地编写。
  • 如果它为语义上相同的查询提供完全不同的执行计划,那将是一个非常糟糕的优化器。
  • 由于我不是使用 Joins 的 SQL 专家,所以 Marc 的建议奏效了。谢谢,马克!
【解决方案2】:

只是猜测您可能还想要总和而不是单个转发记录...这是一个聚合 EmployeeVacations 每个 EmployeeId 的查询:

select
  e.pin,
  e.firstname,
  e.lastname,
  e.uniform,
  e.al_cap,
  ev.forward_sum as "10/1 balance",
  ev.taken_sum as taken
from employee e
left join
(
  select     
    employeeid,
    sum(case when vacation_type = 'Forward' 
             and ishistory = 0 then value else 0 end) as forward_sum,
    sum(case when vacation_type = 'Taken' 
             and creationdate >= '20161001' then value else 0 end) as taken_sum,
  from employeevacations
  where vacation_kind = 'AL'
  group by employeeid
) ev on ev.employeeid = e.employeeid
order by e.lastname, e.firstname;

请...

  • 使用显式连接而不是 1992 年以前的逗号分隔连接,以提高可读性并减少出错的可能性。
  • 别名使用双引号;单引号用于字符串文字。
  • 使用“yyyymmdd”作为日期;它是 SQL Server 中支持的日期文字格式。

【讨论】:

  • 我喜欢这个解决方案,它看起来更干净,更有意义。
  • 如何从 ev.forward_sum 中减去 ev.taken_sum 到一个新列中?我尝试将 sum(ev.forward_sum - ev.taken_sum) 作为“10/24 Balance”,但它错误地给了我一个组。谢谢!
  • 如何从ev.forward_sum 中减去ev.taken_sum?好吧,当然是减号:ev.forward_sum - ev.taken_sum。你的额外sum 根本没有意义。
  • 成功了,谢谢!我想我是想多想了。我一直认为 SQL 中的任何计算都需要像在 Excel 电子表格中一样使用 SUM。
猜你喜欢
  • 2012-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-03-30
  • 2015-02-09
相关资源
最近更新 更多