如何基于日期 - 每两周一次聚合SQL数据库中的行 [英] How to aggregate rows in SQL database based on date - fortnightly basis

查看:105
本文介绍了如何基于日期 - 每两周一次聚合SQL数据库中的行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

尊敬的专家,



我在数据库中有以下类型的行结构;



三列 - 用户ID |日期|工作时间

为每个用户填写数据(带有ID),每个日期(2010年1月至2020年12月)和每天的工作时间。



现在,业务流程是用户可以更改工作时间。例如,我通常每两周工作75小时。但是,我想将我的时间从2017年1月改为2017年3月,因为每两周只工作40小时。在这种情况下,系统将仅在这些日期之间编辑小时,剩余小时将保留至2020年12月。



现在我想退出关于我在组织中工作多少小时的报告。由于动态性和随时更改小时的业务流程,我希望得到如下输出;



测试用户01/01/2010至31 / 12/2016每周75小时

测试用户01/01/2017至2017年3月31日每两周40小时

测试用户01/04/2017至31 / 12/2020每周75小时



有谁可以帮我这个?



谢谢。



我尝试了什么:



我尝试过使用游标特定员工并使用向日期添加到日期并比较前两个小时,以查看是否存在按输出要求划分行的差异。但我很困惑,因为它没有达到目的。



请帮帮我。



谢谢。

解决方案

您可以尝试以下代码:

 选择 
选择 MIN(frmDate。日期来自 WorkingLogs frmDate < span class =code-keyword>其中 frmDate.WorkingHours = wh.WorkingHours)[ From Date ],
选择 MAX(toDate。日期 WorkingLogs toDate 其中​​ toDate.WorkingHours = wh.WorkingHours)[ To 日期],
wh.WorkingHours
来自
< span class =code-keyword>选择 distinct [WorkingHours]
来自 [WorkingLogs] 订单 by [WorkingHours])wh - 获取独特工作时间列表,由此我们可以过滤最短和最长工作时间
订单 1 2 3


我想我已经解决了这个问题,但我不确定这是否是有效的方法。请查看下面的代码,如果您认为可以改进,请告诉我。



 声明  @ startdate   datetime  
set @ startdate = ' 2016-10-17 00:00:00.000' - 起始日期

声明 @ result table

fromdate datetime
todate datetime
totalhours decimal 18 2


while @ startdate < = ' 2020-12-31 00:00:00.000'
开始
- 插入当前两周的行
insert < span class =code-keyword> into @ result
select < span class =code-sdkkeyword> @ startdate ,dateadd(D, 13 @ startdate ),sum(wh.Hours)
来自 dbo.UserWorkingHours wh
其中 wh.WorkingDate @ startdate dateadd(D, 13 @ startdate
wh.UserID = 120 9

- 将开始日期设为下一个两周
set @ startdate = dateadd(D, 14 @ startdate

end

- 声明最终结果表
声明 @ fresult table

fromdate datetime
todate datetime
totalhours 十进制 18 2 ),
id int


- 声明一个变量来设置最终结果表行中的ID,这些行与前一个行具有相同的每两周小时数
声明 < span class =code-sdkkeyword> @ id int
set < span class =code-sdkkeyword> @ id = 1

- - 声明游标及相关变量
声明 @ fd datetime
声明 @ td datetime
声明 @th decimal 18 2

声明 rc cursor
选择 r.fromdate,r.todate,r.totalhours 来自 @ result r 订单 r.fromdate

打开 rc
获取下一步来自 rc into @ fd @ td @th
@@ FETCH_STATUS <> -1
开始

- 如果最终结果表中没有行,则插入前一个结果表中的第一个
- < span class =code-comment>它将是起始行,因为光标按日期升序排序
如果 存在选择 1 来自 @ fresult
开始

插入 进入 @ fresult
选择 @ fd ,< span class =code-sdkkeyword> @ t d , @th @ id
结束
其他
开始
- 最终结果表中有行
- 因此获取最后一行总小时数并将其与游标中当前行总小时数进行比较
if 选择 top 1 totalhours 来自 @ fresult order by fromdate desc )<> @ th
开始
- - 小时比较失败,即当前每两周的小时数与前两周不同
- 增加ID并在最终表格中插入行
set @ id = @ id + 1
插入 进入 @ fresult
选择 @ fd @ td ,< span class =code-sdkkeyword> @ th , @ id
end
else
开始
- 当前每两周的小时数与之前的每两周小时数相同
- 在最终结果表中插入包含先前ID的行
insert < span class =code-keyword> into
@ fresult
select < span class =code-sdkkeyword> @ fd , @ td @ th @ id
end

结束
获取下一步来自 rc @ fd @ td @ th
end
close rc
deallocate rc

- select * from @fresult

- 选择不同的结果以及从'日期'开始的MIN'和MAX'到期'和小时
选择 不同
选择 min(fromdate)来自 @ fresult 其中 id = fr.id) as FROMDATE,
选择 max(todate)来自 @ fresult 其中​​ id = fr.id) as TODATE,
fr.totalhours
来自 @ fresult fr





上面的SQL查询给出了以下输出;





< pre lang =SQL> FROMDATE TODATE HOURS_PER_FORTNIGHT
2016-10-17 00:00:00。 000 2016-10 -30 00:00:00。 000 6 00
2016-10-31 00:00:00。 000 2016-12-11 00:00:00。 000 75 00
2016-12-12 00:00:00。 000 2016-12-25 00:00:00。 000 10 00
2016-12-26 0 0:00:00。 000 2020-12-20 00:00:00。 000 75 00
2020-12-21 00:00:00。 000 2021-01-03 00:00:00。 000 67 50







请告诉我如果可以改进的话。


Dear experts,

I have the following kind of structure in the database as rows;

Three columns - User ID | Date | Working hours
Data is filled in for each user (with IDs), each date (from Jan 2010 to Dec 2020) and working hours for each day.

Now, the business process is that a user can change working hours. For example, I normally work 75 hours per fortnight. But, I want to change my hours from January 2017 to March 2017 as working only 40 hours per fortnight. In that case, the system will edit hours between those dates only and the remaining hours will be left as it is up till Dec 2020.

Now I want to pull out a report on how many hours I work in the organisation. Because of the dynamic nature and the business process about changing hours any time, I want to get the output as the following;

Test user 01/01/2010 to 31/12/2016 75 hours per fortnight
Test user 01/01/2017 to 31/03/2017 40 hours per fortnight
Test user 01/04/2017 to 31/12/2020 75 hours per fortnight

Can anyone please help me with this?

Thanks.

What I have tried:

I tried using cursors for any particular employee and using forward addition to dates and comparing previous fortnight hours to see if there was a difference to break the lines as required by the output. But I am confused as it did not serve the purpose.

Please help me.

Thanks.

解决方案

You can try this code:

Select
	(Select MIN(frmDate.Date) From WorkingLogs frmDate Where frmDate.WorkingHours = wh.WorkingHours) [From Date],
	(Select MAX(toDate.Date) From WorkingLogs toDate Where toDate.WorkingHours = wh.WorkingHours) [To Date],
	wh.WorkingHours
From (
select distinct [WorkingHours] 
from [WorkingLogs] Order by [WorkingHours]) wh --get the lists of unique working hours, from this we can filter the min and max date of working hours
Order By 1,2,3


I think I have resolved this issue but I am not sure whether it is the efficient way of doing it. Please look at the code below and let me know if you think this can be improved.

declare @startdate datetime
set @startdate = '2016-10-17 00:00:00.000' --starting point date

declare @result table 
(
	fromdate datetime,
	todate datetime,
	totalhours decimal(18, 2)
)

while @startdate <= '2020-12-31 00:00:00.000'
begin
        --insert a row for the current fortnight
    	insert into @result
		select		@startdate, dateadd(D, 13, @startdate), sum(wh.Hours)
		from		dbo.UserWorkingHours wh
		where		wh.WorkingDate between @startdate and dateadd(D, 13, @startdate)
		and			wh.UserID = 1209
	
        --set the start date as the next fortnight
	set @startdate = dateadd(D, 14, @startdate)
		
end

--declare the final result table
declare @fresult table 
(
	fromdate datetime,
	todate datetime,
	totalhours decimal(18, 2),
	id int
)

--declare a variable to set ID in the final result table rows which are having the same fortnightly hours as the previous one
declare @id int
set @id = 1

--declare cursor and related variables
declare @fd datetime
declare @td datetime
declare @th decimal(18, 2)

declare rc cursor for
select r.fromdate, r.todate, r.totalhours from @result r order by r.fromdate

open rc
fetch next from rc into @fd, @td, @th
while @@FETCH_STATUS <> -1
begin
	
        --if there are no rows in the final result table then insert the first from from the previous result table 
        --it will be the starting row because the cursor is ordered by from date ascending
	if not exists (select 1 from @fresult)
	begin

		insert into @fresult
			select @fd, @td, @th, @id
	end
	else
	begin
		--there are rows in the final result table 
                --so fetch the last row total hours and compare it with the current row total hours in the cursor
		if (select top 1 totalhours from @fresult order by fromdate desc) <> @th
		begin
                        --the hours comparison failed i.e. current fortnightly hours are different than the previous fortnight
                        --increase the ID and insert the row in the final table
			set @id = @id + 1
			insert into @fresult
				select @fd, @td, @th, @id
		end
		else
		begin
                        --current fortnightly hours are same as the previous fortnightly hours 
                        --insert the row in the final result table with the previous ID
			insert into @fresult
				select @fd, @td, @th, @id
		end

	end
	fetch next from rc into @fd, @td, @th
end
close rc
deallocate rc

--select * from @fresult

--select the distinct result along with MIN 'from date' and MAX 'to date' and the hours
select			distinct
				(select min(fromdate) from @fresult where id = fr.id) as FROMDATE,
				(select max(todate) from @fresult where id = fr.id) as TODATE, 
				fr.totalhours
from			@fresult fr



The above SQL query gives me the following output;


FROMDATE	TODATE	HOURS_PER_FORTNIGHT
2016-10-17 00:00:00.000	2016-10-30 00:00:00.000	6.00
2016-10-31 00:00:00.000	2016-12-11 00:00:00.000	75.00
2016-12-12 00:00:00.000	2016-12-25 00:00:00.000	10.00
2016-12-26 00:00:00.000	2020-12-20 00:00:00.000	75.00
2020-12-21 00:00:00.000	2021-01-03 00:00:00.000	67.50




Please let me know if this can be improved.


这篇关于如何基于日期 - 每两周一次聚合SQL数据库中的行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆