You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多
文档控制台
免费开始使用

如何用SQL/.NET按入职月数计算年假余额?原SQL失效求助

解决员工年假余额计算的SQL和.NET实现方案

嘿,我来帮你搞定这个年假计算的问题!首先明确核心规则:员工年假每月累加2.5天,年度上限30天,余额随入职月份数递增但不超过上限。下面分别给出SQL和.NET的可行实现,帮你替代之前失效的代码。


一、SQL实现(适配主流数据库)

核心思路是计算入职日期到当前日期的完整月份数,乘以2.5后限制最大值为30。不同数据库的函数略有差异,以下是常见版本:

1. SQL Server 版本

SELECT 
    EmployeeID,
    EmployeeName,
    HireDate,
    -- 计算入职至今的完整月份数(考虑日期日部分,确保满整月才计数)
    CASE 
        WHEN DAY(GETDATE()) >= DAY(HireDate) 
        THEN DATEDIFF(MONTH, HireDate, GETDATE())
        ELSE DATEDIFF(MONTH, HireDate, GETDATE()) - 1
    END AS MonthsEmployed,
    -- 计算年假余额,取累加值与30天的较小值
    CAST(MIN(
        CASE 
            WHEN DAY(GETDATE()) >= DAY(HireDate) 
            THEN DATEDIFF(MONTH, HireDate, GETDATE()) * 2.5
            ELSE (DATEDIFF(MONTH, HireDate, GETDATE()) - 1) * 2.5
        END, 
        30.0
    ) AS DECIMAL(5,1)) AS AnnualLeaveBalance
FROM Employees
GROUP BY EmployeeID, EmployeeName, HireDate;

说明

  • CASE判断当前日期的日是否大于等于入职日,确保只有满整月才计入月份数(比如入职1月15日,当前3月14日,只算2个月)
  • MIN函数限制余额不超过30天,DECIMAL(5,1)保证保留一位小数(和示例的7.5天格式一致)

2. MySQL / PostgreSQL 版本

这两个数据库支持LEAST函数,写法更简洁:

SELECT 
    EmployeeID,
    EmployeeName,
    HireDate,
    -- 计算完整月份数
    CASE 
        WHEN DAY(CURRENT_DATE) >= DAY(HireDate) 
        THEN TIMESTAMPDIFF(MONTH, HireDate, CURRENT_DATE)
        ELSE TIMESTAMPDIFF(MONTH, HireDate, CURRENT_DATE) - 1
    END AS MonthsEmployed,
    -- 计算年假余额
    LEAST(
        CASE 
            WHEN DAY(CURRENT_DATE) >= DAY(HireDate) 
            THEN TIMESTAMPDIFF(MONTH, HireDate, CURRENT_DATE) * 2.5
            ELSE (TIMESTAMPDIFF(MONTH, HireDate, CURRENT_DATE) - 1) * 2.5
        END, 
        30.0
    ) AS AnnualLeaveBalance
FROM Employees;

二、.NET(C#)实现

如果需要在业务代码中计算,这里提供一个精确的方法,考虑日期的日部分,确保只有满整月才累加:

public static decimal CalculateAnnualLeaveBalance(DateTime hireDate, DateTime currentDate)
{
    // 基础月份差:年份差*12 + 月份差
    int baseMonths = (currentDate.Year - hireDate.Year) * 12 + (currentDate.Month - hireDate.Month);
    
    // 如果当前日期的日小于入职日,说明还没到当月的入职纪念日,减去1个月
    if (currentDate.Day < hireDate.Day)
    {
        baseMonths--;
    }
    
    // 确保月份数不小于0(避免入职日期晚于当前的异常情况)
    int validMonths = Math.Max(baseMonths, 0);
    
    // 计算累加的年假天数,再限制上限
    decimal leaveDays = validMonths * 2.5m;
    return Math.Min(leaveDays, 30.0m);
}

使用示例

DateTime hireDate = new DateTime(2024, 1, 1);
DateTime currentDate = new DateTime(2024, 4, 1);
decimal balance = CalculateAnnualLeaveBalance(hireDate, currentDate);
Console.WriteLine(balance); // 输出:7.5

说明

  • 处理了入职日期晚于当前日期的异常情况(返回0)
  • decimal类型避免浮点数精度问题
  • 严格按照“满整月”的逻辑累加,和你给出的示例完全匹配

关键注意点

  • 如果你的业务规则是“入职当月就按全月算”(不管是否满整月),可以去掉判断日期日部分的逻辑,直接用DATEDIFF(MONTH, HireDate, GETDATE())baseMonths计算
  • 若需要考虑员工已使用的年假,只需在计算结果中减去已使用天数即可

内容的提问来源于stack exchange,提问作者Md Farid

火山引擎 最新活动