Sql server 根据结果从WHILE循环中的另一个表中进行选择
基本上,我试图根据轮班和输入的天数计算用户可以拥有的总小时数 例如: 2020年9月13日开始换班。根据其他计算,我知道这是第一周,周日。 所以我需要把星期天的2号,然后第二周的3,2,1,1,2号放到轮值桌上 总共7天: 第1周=星期日 第2周=周一、周二、周三、周四、周五、周六Sql server 根据结果从WHILE循环中的另一个表中进行选择,sql-server,tsql,dynamic-sql,sp-executesql,Sql Server,Tsql,Dynamic Sql,Sp Executesql,基本上,我试图根据轮班和输入的天数计算用户可以拥有的总小时数 例如: 2020年9月13日开始换班。根据其他计算,我知道这是第一周,周日。 所以我需要把星期天的2号,然后第二周的3,2,1,1,2号放到轮值桌上 总共7天: 第1周=星期日 第2周=周一、周二、周三、周四、周五、周六 ROTA table +------+-----+-----+-----+-----+-----+-----+-----+ | WEEK | MON | TUE | WED | THU | FRI | SAT |
ROTA table
+------+-----+-----+-----+-----+-----+-----+-----+
| WEEK | MON | TUE | WED | THU | FRI | SAT | SUN |
+------+-----+-----+-----+-----+-----+-----+-----+
| 1 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
| 2 | 3 | 2 | 1 | 1 | 1 | 2 | 1 |
| 3 | 1 | 2 | 1 | 1 | 1 | 1 | 1 |
| 4 | 1 | 1 | 1 | 1 | 2 | 1 | 1 |
| 5 | 1 | 1 | 2 | 1 | 1 | 1 | 1 |
+------+-----+-----+-----+-----+-----+-----+-----+
上述数字存储在移位表中。因此,对于我的7天,这7天的总小时数为2,3,2,1,1,2=51.5小时
SHIFTS Table
+-------+-------+
| SHIFT | HOURS |
+-------+-------+
| 1 | 8.5 |
| 2 | 6 |
| 3 | 8 |
+-------+-------+
我正在做一个WHILE循环来获取所需的周和专栏。所以对于上面的例子,我只需要ROTA表中的SUN列。下一个循环将给我周一到周六
起初我试图把这两行合并在一起,然后我可以做一些计数。所以有3次移位2,1次移位3和3次移位1。然后,我可以得到总小时数,但不知道如何做到这一点
当我的查询完成时,我将得到以下两行:
LOOP 1:
+-----+
| SUN |
+-----+
| 2 |
+-----+
LOOP 2:
+-----+-----+-----+-----+-----+-----+
| MON | TUE | WED | THU | FRI | SAT |
+-----+-----+-----+-----+-----+-----+
| 3 | 2 | 1 | 1 | 1 | 2 |
+-----+-----+-----+-----+-----+-----+
我已经将我的查询向后剥离了一点,但其要点如下:
WHILE @cnt <= @totalDays
BEGIN
IF @dayOfWeek = 1 SET @columnList = 'SUN' ELSE
IF @tempTotalDays >= 7 SET @columnList = 'MON, TUE, WED, THU, FRI, SAT, SUN' ELSE
IF @tempTotalDays = 6 SET @columnList = 'MON, TUE, WED, THU, FRI, SAT' ELSE
IF @tempTotalDays = 5 SET @columnList = 'MON, TUE, WED, THU, FRI' ELSE
IF @tempTotalDays = 4 SET @columnList = 'MON, TUE, WED, THU' ELSE
IF @tempTotalDays = 3 SET @columnList = 'MON, TUE, WED' ELSE
IF @tempTotalDays = 2 SET @columnList = 'MON, TUE' ELSE
IF @tempTotalDays = 1 SET @columnList = 'MON'
SET @sqlCommand = 'select '+ @columnList +' from dbo.ROTA
where WEEK = @rotaWeek'
EXEC sp_executesql @sqlCommand, N'@rotaWeek nvarchar(75), @rotaWeek = @rotaWeek
END;
GO
正如你所看到的,我就快到了。我只是不知道如何计算我的结果,如何从轮班表中选择时间。RoTA表对于我们人类来说是非常可读的,但对于DBMS来说,它不知道一个星期的星期日是下个星期的星期一,或者我们认为表中的值与Mun-Touth-Tou-FRI坐在太阳下的值相邻。 您可以将表格转换为机器可读的形式,第一周的天数为1,2,3,4,5,6,7,第二周的天数为8,9,10,11,12,13,14,等等。计算天数的公式为:day_number=day_of_week+7*week-1 查询:
with days as
(
select 1 + (7 * (week - 1)) as daynum, mon as shift from rota
union all
select 2 + (7 * (week - 1)) as daynum, tue as shift from rota
union all
select 3 + (7 * (week - 1)) as daynum, wed as shift from rota
union all
select 4 + (7 * (week - 1)) as daynum, thu as shift from rota
union all
select 5 + (7 * (week - 1)) as daynum, fri as shift from rota
union all
select 6 + (7 * (week - 1)) as daynum, sat as shift from rota
union all
select 7 + (7 * (week - 1)) as daynum, sun as shift from rota
)
select sum(s.hours)
from days d
join shifts s on s.shift = d.shift
where d.daynum between @dayOfWeek + (7 * (@rotaWeek - 1))
and @dayOfWeek + (7 * (@rotaWeek - 1)) + @totalDays - 1;
当然,如果您更改了数据模型以匹配我的即席日视图,那么查询将减少到上述查询的最后五行
更新:
在请求评论中,您表示希望继续第5周和第1周。您可以使用模运算从第35天到下一天的第1天。\u daynum=daynum%35+1。但这样一来,这就变成了一个迭代过程,每周轮班制甚至可以在计算中使用不止一次。迭代是通过SQL中的递归查询完成的:
with days as
(
select 1 + (7 * (week - 1)) as daynum, mon as shift from rota
union all
select 2 + (7 * (week - 1)) as daynum, tue as shift from rota
union all
select 3 + (7 * (week - 1)) as daynum, wed as shift from rota
union all
select 4 + (7 * (week - 1)) as daynum, thu as shift from rota
union all
select 5 + (7 * (week - 1)) as daynum, fri as shift from rota
union all
select 6 + (7 * (week - 1)) as daynum, sat as shift from rota
union all
select 7 + (7 * (week - 1)) as daynum, sun as shift from rota
)
, cte (daynum, remaining, hours) as
(
select d.daynum, @totalDays - 1, s.hours
from days d
join shifts s on s.shift = d.shift
where d.daynum = @dayOfWeek + (7 * (@rotaWeek - 1))
union all
select d.daynum, cte.remaining - 1, cast(cte.hours + s.hours as decimal(5,1))
from cte
join days d on d.daynum = cte.daynum % 35 + 1
join shifts s on s.shift = d.shift
where cte.remaining >= 1
)
select max(hours)
from cte;
不幸的是,SQL Server要求递归CTE中的强制转换与列的确切数据类型匹配
演示:SQL是一种基于集合的语言。你不需要循环。在最坏的情况下,您可以将所有这些检查转换为回复的QueryTanks的SELECT部分中的单个case子句。如果我只是使用SELECT,当我可能需要多次使用同一周行时,它是如何工作的?什么时候你必须考虑一周多次?你的意思是第5周之后又是第1周,@totalDays可以超过35天吗?是的。可能会有35天以上,第5周后会回到第1周,这对我来说并不清楚。我已经用递归查询更新了我的答案,谢谢。我将尝试将其纳入我最初的查询中,以获取准确的轮班时间。