是否有针对此问题的基于集合的解决方案?

DCN*_*YAM 5 sql sql-server-2005

我们有一个表格如下:

|ID|EmployeeID|Date     |Category       |Hours|
|1 |1         |1/1/2010 |Vacation Earned|2.0  |
|2 |2         |2/12/2010|Vacation Earned|3.0  |
|3 |1         |2/4/2010 |Vacation Used  |1.0  |
|4 |2         |5/18/2010|Vacation Earned|2.0  |
|5 |2         |7/23/2010|Vacation Used  |4.0  |
Run Code Online (Sandbox Code Playgroud)

业务规则是:

  • 休假余额的计算方法是度假减去假期.
  • 使用的假期始终首先应用于最早的度假收入金额.

我们需要返回Vacation Earned的行,这些行没有被使用的假期抵消.如果使用的假期仅抵消了度假获得记录的一部分,我们需要返回显示差异的记录.例如,使用上表,结果集如下所示:

|ID|EmployeeID|Date     |Category       |Hours|
|1 |1         |1/1/2010 |Vacation Earned|1.0  |
|4 |2         |5/18/2010|Vacation Earned|1.0  |
Run Code Online (Sandbox Code Playgroud)

请注意,记录2被删除,因为它被使用时间完全抵消,但记录1和4仅部分使用,因此它们被计算并返回.

我们想到的唯一方法是将所有度假获得的记录放在临时表中.然后,获取使用的总休假并循环通过临时表,删除最旧的记录并从使用的总休假中减去该值,直到使用的总假期为零.我们可以清理它,因为剩下的假期只是最古老的度假记录的一部分.这将使我们留下优秀的度假收入记录.

这有效,但效率很低,表现不佳.此外,随着越来越多的记录被添加,性能将随着时间的推移而降低.

对于更好的解决方案有什么建议吗?如果没有,我们只需要这样做.

编辑:这是供应商数据库.我们无法以任何方式修改表结构.

Gab*_*oli 2

下面应该这样做..

(但正如其他人提到的,最好的解决方案是调整剩余假期的使用情况..)

select 
    id, employeeid, date, category, 
    case 
    when  earned_so_far + hours - total_spent > hours then 
        hours 
    else 
        earned_so_far + hours - total_spent
    end as hours
from 
    (
                select 
                    id, employeeid, date, category, hours,
                    (
                        select 
                            isnull(sum(hours),0)
                        from 
                            vacations 
                        WHERE 
                            category = 'Vacation Earned' 
                            and 
                            date < v.date
                            and
                            employeeid = v.employeeid
                    ) as earned_so_far,
                    (
                        select
                            isnull(sum(hours),0)
                        from
                            vacations
                        where 
                            category = 'Vacation Used'
                            and 
                            employeeid = v.employeeid
                    ) as total_spent
                from 
                    vacations V
                where category = 'Vacation Earned'
    ) earned
where
    earned_so_far + hours > total_spent
Run Code Online (Sandbox Code Playgroud)

逻辑是

  1. 计算每一行迄今为止earned获得的小时数
  2. 计算该用户使用的总小时数
  3. 如果total_hours_so_far + 该记录的小时数-total_spent_hours > 0,则选择该记录