Sql将日期范围拆分为周,然后根据结果计算百分比
我环顾四周,发现有一些与我类似的问题,我的用例略有不同。我可以管理基本的sql,但我需要一些工作 所以我的用例是我有一个折线图报告,我需要为它创建一个存储过程。我有一个签入表,如下所示。我需要做的是计算在每种地点花费的小时数,然后将每周花费的时间分开绘制折线图 我为饼图做了类似的事情。不过,这个过程并不完美Sql将日期范围拆分为周,然后根据结果计算百分比,sql,sql-server,Sql,Sql Server,我环顾四周,发现有一些与我类似的问题,我的用例略有不同。我可以管理基本的sql,但我需要一些工作 所以我的用例是我有一个折线图报告,我需要为它创建一个存储过程。我有一个签入表,如下所示。我需要做的是计算在每种地点花费的小时数,然后将每周花费的时间分开绘制折线图 我为饼图做了类似的事情。不过,这个过程并不完美 ALTER PROCEDURE [dbo].[sp_Report_TimeSpentAtBase] @startdate as DateTime, @endDate as DateTi
ALTER PROCEDURE [dbo].[sp_Report_TimeSpentAtBase]
@startdate as DateTime,
@endDate as DateTime = null,
@teamID as uniqueidentifier = null,
@userID as uniqueidentifier = null
AS
BEGIN
SELECT
LocationType,
Sum(DATEDIFF(minute, InAt, OutAt)) Seconds
FROM CheckIns
INNER JOIN Locations ON Locations.Id = CheckIns.Location_ID
INNER JOIN [System].[Users] ON CheckIns.User_Id = [System].[Users].Id
WHERE
DATEPART(dw, InAt) NOT IN (1, 7) AND
InAt >= @startdate AND
OutAt IS NOT NULL AND
DATEPART(dw, OutAt) NOT IN (1, 7) AND
(@teamID IS NULL OR [System].[Users].Team_ID = @teamID) AND
(@userID IS NULL OR [System].[Users].ID = @userID) AND
(@endDate IS NULL OR OutAt <= @endDate)
GROUP BY LocationType
END
GO
因此,每个位置类型的每次签入的总分钟数
编辑
所以我目前的进展是
WITH dates as
(
select number, DATEADD(day, number, '20170101') as dt
from master..spt_values
where number between 0 and 1000 AND TYPE ='P'
)
SELECT
l.LocationType,
d.dt,
Sum(DATEDIFF(minute, InAt, OutAt)) as mins
FROM Checkins ci
INNER JOIN Locations l ON l.Id = ci.Location_ID
JOIN dates d
on d.dt between ci.InAt and ci.OutAt
GROUP BY
d.dt, l.LocationType
这是总的想法。边界检查可能需要对边缘情况进行一些调整
/*
Set up data
*/
declare @startDate datetime = '07/01/2018'; -- first day you want included
declare @endDate datetime = '07/15/2018'; -- day AFTER the last you want included
declare @location table (locationId int, locationName varchar(100));
declare @log table (logId int, locationId int, checkIn datetime, checkOut datetime);
insert @location values
(1, 'Location 1'),
(2, 'Location 2');
insert @log values
(1, 1, '07/07/2018 20:00:00', '07/08/2018 06:00:00'),
(2, 1, '07/08/2018 20:00:00', '07/09/2018 06:00:00'),
(3, 1, '07/09/2018 20:00:00', '07/10/2018 06:00:00')
;
/*
Summary by location
*/
select loc.locationId ,
loc.locationName ,
SUM(DATEDIFF(MINUTE, log.checkIn, log.checkOut)) as minutes
from @location loc
inner join @log log on log.locationId = loc.locationId
group by loc.locationId ,
loc.locationName
;
/*
Summary by location and week
*/
with
-- List of weeks. There are other ways to do this.
weeks as (
select @startDate as startDate ,
dateadd(week, 1, @startDate) as endDate
union all
select endDate /*as startDate*/ ,
dateadd(week, 1, endDate) /* as endDate*/
from weeks
where endDate < @endDate
) ,
-- Determine how much time each log entry is in each week.
logWeeks as (
select log.locationId ,
w.startDate as week ,
datediff(
minute ,
case when log.checkIn >= w.startDate then log.checkIn else w.startDate end ,
case when log.checkOut <= w.endDate then log.checkOut else w.endDate end
) as minutes
from @log log
inner join weeks w
on log.checkIn < w.endDate
and log.checkOut >= w.startDate
)
-- Summarize.
select loc.locationId ,
loc.locationName ,
lw.week ,
sum(lw.minutes)
from @location loc
inner join logWeeks lw
on lw.locationId = loc.locationId
group by loc.locationId ,
loc.locationName ,
lw.week
order by loc.locationId ,
lw.week
;
下面是我为我的需求创建的解决方案,它将日期范围划分为给定的时间间隔(周末除外) 我创建了一个将日期范围划分为给定间隔的过程。 另外,创建了1个方法来检查日期是否为weekend,并根据标志值返回下一个/上一个工作日 以下是程序
Alter PROCEDURE DateToInterval
-- Add the parameters for the stored procedure here
@start datetime,
@end datetime,
@interval int
AS
BEGIN
declare @start_run as datetime
declare @end_run as datetime
declare @counter as int
--temp table to store interval
create table #tempinterval(
StartDate datetime,
EndDate datetime,
IntervalCounter varchar(20)
)
--update start, end date if it is weekend
set @start_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@start,'add')
set @end_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@start,'remove')
set @end=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@end,'remove')
set @counter=1
--select @start_run as 'start', @end as 'end'
While(@end_run <= @end)
Begin
--select 'loop'
--adding interval on start date
set @end_run = DATEADD(DAY, @interval-1, cast(@start_run as datetime))
if(@end_run > @end)
BEGIN
set @end_run=@end
END
--to check if it is weekend and replace it week next weekdays
set @end_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@end_run,'add')
insert into #tempinterval(StartDate,EndDate,IntervalCounter) values(@start_run,@end_run,'Interval '+ cast(@counter as varchar))
set @end_run=DATEADD(DAY, 1, cast(@end_run as datetime))
--update end date if it is weekend
set @end_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@end_run,'add')
set @start_run=@end_run
set @counter =@counter + 1
END
select * from #tempinterval
END
GO
虽然您提供了大量恭敬的描述,但不幸的是,这并不是对回答者最有帮助的。最好为您拥有的每个表以及select查询的结果行提供一些示例行。如果您有一个“weeks”表,其中包含每周的开始时间,会更容易吗?您可以将week表交叉连接到location表,然后对于每个week和location,您可以连接到该周内有时间的签入。他们可以计算时间,如果他们在一周内登记入住和退房,那么这可能是部分时间,然后你可以分组总结。您的“weeks”表可以是一个静态表,以使事情顺利进行,但最终您可能希望使用WITH@GeorgeMenoutis我编辑了问题并添加了一些示例数据,以及当前存储过程的结果。嘿,你能在问题中粘贴脚本而不仅仅是图片吗P@connorg98你没问题:谢谢,这正是我所需要的:
Alter PROCEDURE DateToInterval
-- Add the parameters for the stored procedure here
@start datetime,
@end datetime,
@interval int
AS
BEGIN
declare @start_run as datetime
declare @end_run as datetime
declare @counter as int
--temp table to store interval
create table #tempinterval(
StartDate datetime,
EndDate datetime,
IntervalCounter varchar(20)
)
--update start, end date if it is weekend
set @start_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@start,'add')
set @end_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@start,'remove')
set @end=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@end,'remove')
set @counter=1
--select @start_run as 'start', @end as 'end'
While(@end_run <= @end)
Begin
--select 'loop'
--adding interval on start date
set @end_run = DATEADD(DAY, @interval-1, cast(@start_run as datetime))
if(@end_run > @end)
BEGIN
set @end_run=@end
END
--to check if it is weekend and replace it week next weekdays
set @end_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@end_run,'add')
insert into #tempinterval(StartDate,EndDate,IntervalCounter) values(@start_run,@end_run,'Interval '+ cast(@counter as varchar))
set @end_run=DATEADD(DAY, 1, cast(@end_run as datetime))
--update end date if it is weekend
set @end_run=DBTest.dbo.Check_Weekend_And_Update_With_WeekDays(@end_run,'add')
set @start_run=@end_run
set @counter =@counter + 1
END
select * from #tempinterval
END
GO
Alter FUNCTION Check_Weekend_And_Update_With_WeekDays
(
@date date,
@flag varchar(10) --flag to add or removed dates to get the weekdays
)
RETURNS datetime
AS
BEGIN
-- Declare the return variable here
DECLARE @ResultVar date
--1 (Sunday) or 7 (Saturday)
IF DATEPART(W, @date) in (1,7)
BEGIN
IF(DATEPART(W, @date)=1) --IF sunday
BEGIN
IF(@flag='add')
BEGIN
set @date=DATEADD(DAY, 1, cast(@date as datetime))
END
ELSE
BEGIN
set @date=DATEADD(DAY, -2, cast(@date as datetime))
END
END
ELSE
BEGIN
IF(@flag='add') --If Saturday
BEGIN
set @date=DATEADD(DAY, 2, cast(@date as datetime))
END
ELSE
BEGIN
set @date=DATEADD(DAY, -1, cast(@date as datetime))
END
END
END
set @ResultVar=@date
-- Return the result of the function
RETURN @ResultVar
END
GO