【问题标题】:Counting between date ranges在日期范围之间计数
【发布时间】:2015-08-20 19:54:53
【问题描述】:

我有很多员工假期记录,其中显示了假期的开始和结束日期。我需要计算出每个员工在两个日期之间度过了多少假期,即2015-01-01 00:00:002015-02-01 00:00:00

如何处理假期开始于该范围之前或结束于该范围之后的假期?

  • 例如,如果employee 1起飞2015-01-102015-01-15,那就是5天假期

  • 但如果employee 2起飞2015-12-252015-01-05,那应该只算5天假期

  • 另一边也一样,即如果employee 3起飞2015-01-252015-02-05,那应该只算5天假期

【问题讨论】:

  • 通过示例输出和所需结果,您的问题会更加清晰。
  • 你需要一个包含所有日期的日历,告诉它是否是工作日。

标签: sql sql-server sql-server-2008


【解决方案1】:

您使用日期逻辑。其他数据库有 least()greatest() 函数来帮助解决这个问题。在 SQL Server 中,您可以使用更复杂的 case 语句。结果是这样的:

select h.employee_id,
       sum(datediff(day, 
                    (case when h.start < @StartDate then @StartDate else h.start end),
                    (case when h.end > @EndDate then @EndDate else h.end end)
                   )
          ) as DaysOnHoliday
from holidays h
where h.start <= @EndDate and h.end >= @StartDate
group by h.employee_id

【讨论】:

  • 虽然LEAST()GREATEST() 很可爱,但它们真的可以咬NULLABLE 数据。 MIN({NULL, 0}) =&gt; 0LEAST(NULL, 0) =&gt; NULLCASE 语句更长,但提供更明确的控制:)
【解决方案2】:

假设您的员工假期表如下所示:

CREATE TABLE EmployeeHoliday (
    EmployeeId INT,
    HolidayStart DATETIME,
    HolidayEnd DATETIME
)

以下查询返回两个指定日期(变量)之间每位员工的天数:

DECLARE @CountFromDate AS DATETIME = '2015-01-01'
DECLARE @CountToDate AS DATETIME = '2015-02-01'

SELECT EmployeeId,
    SUM(DATEDIFF(DAY,
        CASE WHEN @CountFromDate < HolidayStart THEN HolidayStart ELSE @CountFromDate END,
        CASE WHEN @CountToDate > HolidayEnd THEN HolidayEnd ELSE @CountToDate END
        )
    ) AS HolidaysHeld
FROM EmployeeHoliday
GROUP BY EmployeeId

如果您不希望此查询输出仅在指定时间间隔之外有假期的员工,请在查询的 GROUP BY 部分之前包含以下 WHERE 子句:

WHERE HolidayStart <= @CountToDate AND HolidayEnd >= @CountFromDate

【讨论】:

  • 我犹豫要不要给 +1,因为这没有 WHERE 子句 (返回 0 天可能是表的绝大多数;对于不与指定重叠的假期range),但确实明确说明了假定的架构。
  • 这是故意的,因为一些用例包括知道哪些员工在所选期间没有任何假期...
  • 那么我建议加入员工表;就目前而言,它仅对有假期且没有人在该日期范围内的员工给出 0,但会错过尚未拥有或预订任何假期的新员工。
  • 你是对的。向问题添加评论以解决这一点。
【解决方案3】:
declare @datebeg datetime = '20150101', @dateend datetime = '20150201'

select e.employeeid, sum(datediff(day, case when @datebeg < h.datebeg then h.datebeg else @datebeg end,
                                       case when @dateend > h.dateend then h.dateend else @dateend end))
from holiday h 
where @datebeg <= h.dateend and @dateend >= h.datebeg
group by h.employeeid

【讨论】:

    【解决方案4】:

    你试试 SELECT date1-date2 from tablename;

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-02-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-10-16
      • 2019-02-14
      相关资源
      最近更新 更多