我正在尝试查找一个SQL查询,该查询将计算至少30分钟不同的不同开始时间的数量。
我有一些员工在一周内至少三个不同时间开始工作时获得学分,其中开始时间与其他开始时间至少相差30分钟。 例如:
select count(distinct (CONVERT(VARCHAR(10), starttime, 108))), employeecode
from schedule
where CONVERT(VARCHAR(10), starttime, 108) >=
(select min(CONVERT(VARCHAR(10), dateadd (mi, 30, s2.starttime), 108)) from schedule s2)
group by starttime, employeecode
我希望通过员工代码和不同且不同的开始时间来获得结果。例如。 Employeecode = 9999,不同的开始时间= 4 我一直在笨手笨脚,但还没有得到一些工作......
任何人都可以建议我出错的地方或可能对我有帮助的合适解决方案吗? 在此先感谢您的帮助:)
答案 0 :(得分:1)
在等待确切要求的澄清时,我认为我建议采用另一种方法。我会用它来衡量它的优缺点......
如果开始时间通常在某个时间或某个时间左右(你的例子总是在半小时或一小时),那么你可以将所有开始时间分成他们所在的“乐队”然后计算不同频段的数量。
例如00:00-00:30 =乐队1 00:30-01:00 =乐队2 ... 07:00-07:30 =乐队15 ... 23:30-00:00 =乐队48
要获得乐队,你只需要一个简单(虽然相当冗长)的案例陈述。
这种方法的主要问题是,当您的时间接近阈值时,它会崩溃。例如,07:29和07:31将分为两个不同的乐队,但事实上相隔只有2分钟。如果您大约在同一时间开始,通过让乐队在每小时过去15分钟和45分钟开始和结束,这可以略微减轻。然后,如果开始时间都在乐队的中间,那么你将得到它大部分正确......
在我的脑海中虽然问题不是真正适合SQL的问题,所以如果你能用不同的语言做到这一点可能会更好......
你可能会在SQL中使用一些棘手的连接来完成它但是我无法为它编写可靠的SQL ...但是在算法上你想要做以下事情。
1)在当天采取最早的开始时间并将其称为您的第一个开始时间。 2)采取下一个最早的时间,比你上一步的时间晚至少30分钟。 3)重复步骤2,直到用完为止。 4)计算时间。
从SQL的角度来看,问题在于它正在尝试基于前一行创建数据,这意味着使用游标来循环遍历您的时间并将内容存储在变量中。
答案 1 :(得分:0)
[更新:根据海报在对这个答案的评论中对问题的澄清,我用这个答案解决的问题显然不是海报试图解决的问题。我将离开答案,以便显示其他问题的解决方案,以免删除澄清问题陈述的评论]
将问题分为两部分:识别“唯一”(在30分钟内)开始然后计算它们。第一部分是我觉得你遇到麻烦的那部分。这是一种方法:
SELECT employeecode, starttime FROM schedule S1
WHERE NOT EXISTS (SELECT * FROM schedule S2
WHERE S2.employeecode = S1.employeecode AND
S2.starttime > DATEADD(mi, -29, S1.starttime)
一些注意事项:
我从原始查询中复制了日期数学逻辑,而不是查找语法。
我认为starttime是DATETIME。
我用了29分钟,如果开始时间相隔30分钟或更长时间(如问题陈述中所述),他们就会得到奖金。实际上,你应该通过使用秒进行日期数学并减去(29 * 60)+ 59来做到这一点。对于员工来说,我的版本比你的问题陈述指定的更为慷慨。
您可以将此查询封装在视图或内部查询中,并执行类似的操作(假设它是一个视图):
选择employeecode,count()FROM unique_starts_view 在哪里开始时间BETWEEN(期间开始)AND(期末) GROUP BY员工代码具有COUNT()> = 3
NOT EXISTS技术可能很慢,因此最好将查询限制在您感兴趣的时间段内。
答案 2 :(得分:0)
我假设您的数据库产品是基于您的OP的SQL Server,但您没有提到该版本。如果您使用的是SQL Server 2005及更高版本,则可以尝试以下方法:
With StartTimes As
(
Select StartDateTime
, Row_Number() Over( Order By StartDateTime ) As Seq
, DatePart(hh, StartDateTime) * 60 + DatePart(mi, StartDateTime) As Minutes
From Schedule
)
Select *
From StartTimes As S1
Where Exists(
Select 1
From StartTimes As S2
Where S1.Seq <> 1
And Abs(S2.Minutes - S1.Minutes) >= 30
)
答案 3 :(得分:0)
使用克里斯提到的时间段(不要与时间强盗混淆):
CREATE TABLE Start_Periods
(
begin_time TIME NOT NULL,
end_time TIME NOT NULL,
time_period TINYINT NOT NULL
CONSTRAINT PK_Start_Periods PRIMARY KEY CLUSTERED (begin_time),
CONSTRAINT CK_Start_Periods_begin_before_end CHECK (begin_time < end_time OR end_time = '00:00:00.000')
)
INSERT INTO Start_Periods (begin_time, end_time, time_period)
SELECT '00:00:00.000', '00:15:00.000', 1 UNION ALL
SELECT '00:15:00.000', '00:45:00.000', 2 UNION ALL
SELECT '00:45:00.000', '01:15:00.000', 3 UNION ALL
SELECT '01:15:00.000', '01:45:00.000', 4 UNION ALL
SELECT '01:45:00.000', '02:15:00.000', 5 UNION ALL
SELECT '02:15:00.000', '02:45:00.000', 6 UNION ALL
SELECT '02:45:00.000', '03:15:00.000', 7 UNION ALL
SELECT '03:15:00.000', '03:45:00.000', 8 UNION ALL
--...
SELECT '23:15:00.000', '23:45:00.000', 48 UNION ALL
SELECT '23:45:00.000', '00:00:00.000', 1
您的查询将变为:
SELECT
SCH.employee_code,
COUNT(DISTINCT SP.time_period) AS different_time_starts
FROM
Schedule SCH
INNER JOIN Start_Periods SP ON
SP.begin_time <= SCH.start_time AND
SP.end_time > SCH.start_time
GROUP BY
SCH.employee_code
答案 4 :(得分:0)
只是为了给你一个想法:
SELF JOIN
schedule
DISTINCT
同时从另一个人那里开始时间这应该会给你想要的结果。