Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/83.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 根据期间规则动态获取假日期间_Sql_Sql Server - Fatal编程技术网

Sql 根据期间规则动态获取假日期间

Sql 根据期间规则动态获取假日期间,sql,sql-server,Sql,Sql Server,每个员工都有假期政策。这项假期政策让我知道以下几点: 根据工作年限的不同,假期可能会有所变化 根据工作年数,每个周期允许的最大天数是多少 例如: 该员工于2011年10月10日加入公司 第一个工作年度2012年10月10日,员工有6天假期可供使用。但仅在第一年,该日期必须在2012年10月10日至2012年12月31日期间使用 因此,规则是: 1个工作年度-期间开始:员工加入日期:当年的JODA至年底。 对于接下来的所有年份,规则为:>1个工作年-期初:1/1/年至12/31/年。 此规则位于具

每个员工都有假期政策。这项假期政策让我知道以下几点:

根据工作年限的不同,假期可能会有所变化

根据工作年数,每个周期允许的最大天数是多少

例如:

该员工于2011年10月10日加入公司

第一个工作年度2012年10月10日,员工有6天假期可供使用。但仅在第一年,该日期必须在2012年10月10日至2012年12月31日期间使用

因此,规则是:

1个工作年度-期间开始:员工加入日期:当年的JODA至年底。 对于接下来的所有年份,规则为:>1个工作年-期初:1/1/年至12/31/年。 此规则位于具有以下架构的表中:

0年是指所有年份

我对startperiod和endperiod列使用了varchar4数据类型

下表列出了每个工作年允许的最大天数:

所以我需要的结果是这样的:

第一行,期间根据工作年=1的规则开始,其余行的期间从一年的第一天开始,到一年的最后一天结束

我已经用相同的列和数据创建了一个SQL FIDLE

我的问题是,我不知道如何在不使用光标的情况下在一次选择中获得所有时段


我很感激任何关于如何做的帮助和建议。这似乎不是一项简单的任务。

从加入一个数字表开始,这样每个员工每年都可以得到一行

SELECT * --change this
FROM dbo.hd_employee e
JOIN 
dbo.nums n 
   ON n.num <= datediff(year, hd.joindate, getdate()) + 1
LEFT JOIN dbo.hd_workingyear_days wyd
    ON wyd.year = n.num
LEFT JOIN dbo.hd_workingyear_days wyd0
    ON wyd.year IS NULL
    AND wyd0.year = 0

现在,您可以轻松地应用您的逻辑,因为您有年份编号,您可以计算年初,并根据需要进行比较,依此类推。使用ISNULLwyd.alloweddays、wyd0.alloweddays允许您的“默认值”。

您可以按以下方式尝试在单个查询中获得所需的输出

Select 
subqry2.employeeid,
Subqry2.startdt,
Subqry2.enddt,
Subqry2.workingYears,
Subqry2.alloweddays,
Subqry2.daysused,
(Subqry2.alloweddays-Subqry2.daysused) as remaining
from
(
select 
subqry1.employeeid,
subqry1.startdt,
subqry1.enddt,
subqry1.workingYears,
subqry1.alloweddays,
(select COUNT(1) from 
   hd_employee_holiday subqry 
   where subqry.employeeid = subqry1.employeeid 
   and subqry.date between subqry1.startdt and subqry1.enddt 
) as daysUsed
from
(
select 
Q1.employeeid,
 -- without using the rule table
 -- Case when Q2.number <= 1 then dateadd(yy,Q2.number,Q1.joindate) else dateadd(yy, datediff(yy,0,dateadd(yy,q2.number,q1.joindate)),0) end StartDt,
 -- DATEADD(yy, DATEDIFF(yy,0,dateadd(yy,q2.number+1,q1.joindate) + 1), -1) EndDt,
 -- using rule table
(select case when startperiod='JODA' then dateadd(yy,q2.number,Q1.joindate) 
         else dateadd(yy,Q2.number,cast(cast(year(Q1.joindate) as varchar) + startperiod as DATE)) end 
 from hd_workingyear_rule Q5 where Q5.year = (case when Q2.number != 1 then 0 else Q2.number end) 
) StartDt,
(select dateadd(yy,Q2.number,cast(cast(year(Q1.joindate) as varchar) + endperiod as DATE)) 
 from hd_workingyear_rule Q5 where Q5.year = (case when Q2.number != 1 then 0 else Q2.number end) 
) EndDt,
Q2.number WorkingYears,
Q3.alloweddays,
Q1.years,
Q2.number 
from
(select employeeid,joindate,datediff(year,joindate,getdate())+1 as years  from hd_employee) Q1
join master..spt_values Q2 on Q2.type = 'P' and Q2.number < Q1.years
join hd_workingyear_days Q3 on (Q2.number) = Q3.year
) subqry1
) Subqry2

这是一个数据模型的示例,它将冗余降至最低,而不利于复杂性。尽管如此,我们并不总能改变数据模型

下面是您问题的解决方案,它使用封装在函数中的CTE生成必要的表格数据

我注意到我对需求的理解不同,你和其他人实现了它。如果结果证明我错了,那么这会给你你描述的结果


您的SQL FIDLE中有一个错误:您在1年级和0年级都使用了JODA。您应该能够使用workingyear_days表作为查询的主表来实现所需的结果,以便每年获得一行,并根据其他列的需要连接到其他表。我只是修复了SQL FIDLE。您是对的。dbo.nums意味着什么?一个数字表。如:创建表dbo.nums num int主键;插入dbo.nums通过从sys.all_列中选择1在订单上选择行_编号;
empid   startdt     enddt   WY  DA  DU  DR
1   2012-10-10  2012-12-31  1   6   3   3
1   2013-01-01  2013-12-31  2   8   2   6
1   2014-01-01  2014-12-31  3   9   4   5