【问题标题】:SQL query that joins two tables and sum from second连接两个表并从第二个求和的 SQL 查询
【发布时间】:2020-08-27 22:31:59
【问题描述】:

我有这个带有示例数据的表格:

日历

身份证 |日期 ---+----------- 1 | 2020-01-01 2 | 2020-01-02 3 | 2020-01-03

员工工作时间

身份证 |日期 |工作时间 |用户身份 ---+------------+--------------+------- 1 | 2020-01-01 | 2 | 2 2 | 2020-01-01 | 4 | 2

我想创建一个 MS-SQL 查询来显示用户没有工作的天数,以及他们还有多少小时可以工作(他们应该每天工作 8 小时)。都在一个时间段内,比如一周。 结果应如下所示:

EmployeeHaveNotWorked

日期 |还剩几小时上班 ------------+---------------- 2020-01-01 | 2

知道如何进行这样的 MS-SQL 查询吗?

【问题讨论】:

    标签: sql sql-server


    【解决方案1】:

    首先获取所有日期的所有用户。这是通过交叉连接完成的。看到您使用的是UserID,我想有一个用户表。否则从EmployeeTimeWorked 表中获取用户。

    然后外部加入每个用户和日期的工作时间。这是一个简单的聚合查询。

    然后从所需的 8 小时中减去工作时间。

    select 
      u.userid, 
      c.date,
      8 - coalesce(w.hours_worked, 0) as hours_left_to_work
    from users u
    cross join calendar c
    left outer join
    (
      select userid, date, sum(hoursworked) as hours_worked
      from employeetimeworked
      group by userid, date
    ) w on w.userid = u.userid and w.date = c.date
    order by u.userid, c.date;
    

    【讨论】:

    • 谢谢,这是一个很好的开始。问题是它返回的行太多(大约 100 000),它应该只返回大约 31(当月的天数)。我尝试使用日期和用户 ID 进行限制,但无法正常工作。
    • 2020 年 8 月,例如:where c.date >= '2020-08-01' and c.date < '2020-09-01'。对于当前月份,例如:where year(c.date) = year(getdate()) and month(date) = month(getdate())。对于用户 #2:and u.userid = 2.
    • 我试过了,还尝试将它限制为仅针对某个用户(userId 2),但我仍然得到大约 200 000 行。我认为交叉连接可能会添加太多行。我的查询:选择 c.date, u.ID, 8 - coalesce(w.hours_worked, 0) as hours_left_to_work from [dbo].[User] u cross join calendar c left outer join ( select ID, date, sum(durationHours)作为 TimeLog 组中的 hours_worked(按 ID、日期) w.ID = u.Id 和 u.Id = 2 和 w.date = c.date AND c.date >= '2020-08-01' 和 c.date
    • 因为您将条件绑定到外部联接的 ON 子句。您需要一个 WHERE 子句。不要ANDON子句的条件,它们与您要外连接的行无关。
    【解决方案2】:

    使用cross join 生成所有可能的行,然后过滤掉存在的行:

    select u.userid, c.date,
           8 - coalesce(sum(HoursWorked), 0) as remaining_time
    from calendar c cross join
         (select distinct userid from EmployeeTimeWorked) u left join
         EmployeeTimeWorked etw
         on etw.userid = u.userid and etw.date = c.date
    where etw.userid is null
    group by u.userid, c.date
    having sum(HoursWorked) < 8
    

    【讨论】:

    • 很好的答案,但缺少聚合。在示例中,用户 #2 在 2020 年 1 月 1 日工作了两次。一次两小时,另外四小时。 8 - (2+4) = 2。因此,我们必须外部加入每个用户和每天的聚合工作时间。
    • 感谢您的回复,而且速度如此之快!该查询的外观如何?
    • @Olof84:您主要将EmployeeTimeWorked 替换为一个子查询,在该子查询中添加每个用户和日期的工作时间,即类似于from (select ...) subq 的内容,然后将所需的数学添加到你的选择子句(8hrs-sum)。
    • @ThorstenKettner 。 . . where 子句过滤两条记录就像过滤一条记录一样容易。
    • 我不知道你的意思,你能写下查询吗?
    【解决方案3】:

    这个查询似乎帮我完成了:

    select * from (select c.Date, 8 - coalesce(sum(t.durationHours),0) hours_left_to_work 
    from Calendar c
    left join TimeLog t on t.Date = c.Date
    where c.date >= '2020-08-01' and c.date <= '2020-08-31'
    group by c.Date) as q1
    where q1.hours_left_to_work IS NOT NULL
    AND q1.hours_left_to_work > 0;
    

    TimeLog = EmployeeTimeWorked

    【讨论】:

      猜你喜欢
      • 2018-10-03
      • 1970-01-01
      • 2018-09-19
      • 2016-05-27
      • 2017-07-05
      • 2020-11-10
      • 2018-02-05
      • 2014-03-23
      相关资源
      最近更新 更多