【问题标题】:Compute range between datetimes in SQL Server 2005 - but only count within specified bounds计算 SQL Server 2005 中日期时间之间的范围 - 但仅在指定范围内计算
【发布时间】:2014-01-23 23:42:17
【问题描述】:

在 SQL Server 2005 中,我有这个要求,我可以在其中获取某些活动的开始和结束日期。

另外,一天中有两个时间段,例如从早上 5 点到早上 9 点和从下午 2 点到下午 6 点,我需要找出这个开始和结束日期在这些时间段内的分钟数。

例如,如果开始时间是 2014 年 1 月 24 日上午 6:30,结束时间是另一天,即 25-01-2014 上午 11 点。结果应该是 24 日上午 9 点 - 6:30,所以 150 分钟和晚上满时段,所以第二天早上 240 分钟满时段,所以 240 分钟

总计 = 150 + 240 + 240。

我正在尝试编写一个函数并在我的查询中使用它。我会将开始和结束日期传递给我的函数。

感谢任何帮助。

我已经开始编写代码,但是它有太多的条件,所以我想最好向比我了解更多 SQL 的人寻求建议。

让我试着解释得更好。

我有两个日期,一个是开始日期,另一个是结束日期,两者都有时间。

现在一天中有两个时间段我感兴趣,想知道这两个日期之间有多少分钟属于这些时间范围。

因此,如果每天的时间段是上午 5 点到 9 点和下午 16 点到 20 点。

我的开始日期和结束日期在这两个时段中的多少分钟?

所以如果开始日期是 24/01/2014 6:30,结束日期是 24/01/2014 17:30。

因此,这两个日期使用 9 - 6:30,因此从第一个时间段 5 点到上午 9 点为 2 小时 30 分钟,而 17:30 - 16:00 = 从第二个时间段开始的 1 小时 30 分钟。

这些开始和结束日期可以是同一天的任何日期,也可以是第二天或之后的 n 天。

【问题讨论】:

  • 我真的不清楚你是如何得出你的解决方案的 - 你能否更清楚地解释你的算法和所需的输出?
  • 您好 user3230006。欢迎来到堆栈溢出。为了更快地获得帮助(并且严格中肯),请与我们一起明确您的问题:首先,向我们展示一些代码!你试过什么?你认为你的函数签名是什么?预期的结果是什么?
  • 对不起 - 我也应该说欢迎!我没看到这是你的第一篇文章。
  • 我已经开始编写代码,但是它有太多的条件,所以我想最好向比我了解更多 sql 的人寻求建议。让我尝试更好地解释。我有两个日期,一个是开始日期,另一个是结束日期,两者都有时间。现在一天中有两个我感兴趣的时间段,想知道这两个日期之间有多少分钟属于这些时间范围。所以如果每天的时间段是早上 5 点到 9 点和下午 16 点到 20 点。
  • 我的开始日期和结束日期在这两个时段中的多少分钟?所以如果开始日期是 24/01/2014 6:30,结束日期是 24/01/2014 17:30。所以这两个日期使用 9 - 6:30,所以从早上 5 点到早上 9 点的第一个时间段有 2 小时 30 分钟,而从第二个时间段开始的 17:30 - 16:00 = 1 小时 30 分钟。这些开始日期和结束日期可以是同一天的任何日期,也可以是下一天或之后的 n 天。

标签: sql sql-server sql-server-2005


【解决方案1】:

我准备了两个用户定义的标量值函数,它们可以在 SQL Server 2005 中缺少 DateTime 功能的情况下使用。请注意,所有小数分钟都会被截断(例如,00:59:59 将被截断为 59 分钟)。

基本前提是我们将时域转换为仅考虑您关心的分钟数。

测试

select dbo.fnDateDiff_SigMinutes('2014-01-24 6:30 AM', '2014-01-24 11:00 AM')  --returns 150
select dbo.fnDateDiff_SigMinutes('2014-01-24 6:30 AM', '2014-01-26 11:00 AM')  --returns 1110
select dbo.fnDateDiff_SigMinutes('2014-01-24 6:30 AM', '2014-01-25 11:00 AM')  --returns 630
select dbo.fnDateDiff_SigMinutes('2014-01-24 6:30 AM', '2014-01-25 5:00 PM')   --returns 810
select dbo.fnDateDiff_SigMinutes('2014-01-24 11:00 AM', '2014-01-27 5:00 PM')  --returns 1620
select dbo.fnDateDiff_SigMinutes('2014-01-24 11:00 AM', '2014-01-27 5:00 AM')  --returns 1200

dbo.fnDateDiff_SigMinutes

CREATE FUNCTION [dbo].[fnDateDiff_SigMinutes](@DateBegin datetime, @DateEnd datetime)
RETURNS int
AS
BEGIN

DECLARE @diff int

--Figure out if the two dates are on the same actual day.
DECLARE @dateOnly_start datetime, @dateOnly_end datetime
select @dateOnly_start = DATEADD(dd, 0, DATEDIFF(dd, 0, @DateBegin))
select @dateOnly_end = DATEADD(dd, 0, DATEDIFF(dd, 0, @DateEnd))

IF @dateOnly_start = @dateOnly_end
begin
    --figure out our minutes
    declare @minuteBegin int, @minuteEnd int
    select @minuteBegin = dbo.fnGetSigMinutes(@DateBegin)
    select @minuteEnd = dbo.fnGetSigMinutes(@DateEnd)

    select @diff = @minuteEnd - @minuteBegin

end
else
begin
--compute the number of days between the two, multiply result by 480
select @diff = (datediff(day, @DateBegin, @DateEnd)) * 480

if (@diff = 0)
    --compute difference between midnight and start, end and midnight
    select @diff = @diff + dbo.fnDateDiff_SigMinutes(@DateBegin, dateadd(minute, 1439, @dateOnly_start))
                         + dbo.fnDateDiff_SigMinutes(@dateOnly_end, @DateEnd)
else
    select @diff = @diff + dbo.fnDateDiff_SigMinutes(@DateBegin, dateadd(day, datediff(day, @DateEnd, @DateBegin), @DateEnd))
end

return @diff

END

dbo.fnGetSigMinutes

CREATE FUNCTION [dbo].[fnGetSigMinutes](@date DateTime)
RETURNS int
AS
BEGIN

/*
Minutes 0-300 do not count
Minutes 300-540 count
Minutes 540-840 do not count
Minutes 840-1080 count
Minutes 1080-1440 do not count

Therefore, you can shift the minute of the day into a your chosen domain using a stepwise transform:
*/
declare @m int,  @ma int  --minute (m), minute_adjusted (ma)
select @m = datediff(minute, DATEADD(dd, 0, DATEDIFF(dd, 0, @date)), @date)
select @ma = 
case when (@m < 300) then 0
     when (@m < 540) then @m - 300
     when (@m < 840) then 240
     when (@m < 1080) then @m - 600 
     else 480
end

return @ma

END

【讨论】:

  • 嗨,哇,这看起来真不错,只有一个问题,这条线是做什么用的? --计算两者之间的总天数,将结果乘以480....为什么要乘以480?
  • 哈!我刚刚意识到那里有一些测试代码需要关闭。固定。
  • 谢谢,我只是想了解您的代码,如果我想将时间段从 5 更改为 9 和 15 更改为 20(而不是 16 到 20),我是否应该相应地更改大小写值?
  • 还有这个选择 dbo.fnDateDiff_SigMinutes('2014-01-24 6:30 AM', '2014-01-26 11:00 AM') 返回 2550?我错过了什么吗?谢谢
  • 对不起,但它也不能按照你给出的例子工作。
【解决方案2】:

一个小的改进。
我尊重 mayer06 的分析、辛勤工作和解决问题。
并且觉得第一个功能可能会精简--

CREATE FUNCTION [dbo].[fnDateDiff_SigMinutes](@DateBegin datetime, @DateEnd datetime)
RETURNS int
AS
BEGIN

DECLARE @diff int

--Figure out if the elapsed days between two dates w/o times, and multiply by 480.
DECLARE @dateOnly_start datetime, @dateOnly_end datetime
select @dateOnly_start = DATEADD(dd, 0, DATEDIFF(dd, 0, @DateBegin))
select @dateOnly_end = DATEADD(dd, 0, DATEDIFF(dd, 0, @DateEnd))
select @diff = (datediff(day, @DateBegin, @DateEnd)) * 480

--figure out our minutes
declare @minuteBegin int, @minuteEnd int
select @minuteBegin = dbo.fnGetSigMinutes(@DateBegin)
select @minuteEnd = dbo.fnGetSigMinutes(@DateEnd)

-- compute the total difference
select @diff = @diff + @minuteEnd - @minuteBegin


return @diff

END

原始解决方案应归功于 mayer06。

【讨论】:

  • 赞成 - 我做了这件事后意识到这是可以做到的 - 但应该像你一样应用它。当你真的很晚起床时,就会发生这种情况。
  • 您好 mayer06,当您修复代码时,我一直在 MSAccess 中进行 CYA 并行开发,并随时准备救援。但是你解决了问题......我会用 Declare MinPerDay 替换 480 然后有一个 Select MinPerDay = dbo.fnGetSigMinutes("11:59:59 PM") 并将所有 ShiftDurations 保留在较低级别的函数中。请求者正在考虑更改开始/结束,也许还有班次的数量......此外,fnGetSigMinutes 中的更多 cmets 将分钟与时间联系起来......例如--300 = 上午 5:00。否则,太棒了
  • 感谢 Mayer 和 Don 帮助我解决这个问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-01-19
  • 1970-01-01
  • 2019-02-14
相关资源
最近更新 更多