【问题标题】:Extracting time availability from my calendar table从我的日历表中提取时间可用性
【发布时间】:2021-01-02 04:27:16
【问题描述】:

我的桌子上有一个日历,我应该取出每个月的设备可用性,直到今天。 表格如下:

create table period
(GCP_START date, GCP_END date, 
 GCP_MONSTART int, GCP_MONEND int, 
 GCP_TUESSTART int, GCP_TUESEND int,
 GCP_WEDSTART int, GCP_WEDEND int, 
 GCP_THURSSTART int, GCP_THURSEND int,
 GCP_FRISTART int, GCP_FRIEND int,
 GCP_SATSTART int, GCP_SATEND int,
 GCP_SUNSTART int, GCP_SUNEND int);
 
 insert into period values
 ('2020-10-25', '2020-10-31', 360, 1320, 360, 1320, 360, 1320, 360, 1320, 360, 1320, NULL, NULL, NULL, NULL), 
('2020-11-01', '2020-11-30', 360, 1320, 360, 1320, 360, 1320, 360, 1320, 360, 1320, NULL, NULL, NULL, NULL), 
('2020-12-01', '2020-12-23', 360, 1320, 360, 1320, 360, 1320, 360, 1320, 360, 1320, NULL, NULL, NULL, NULL), 
('2020-12-24', '2020-12-24', 360, 720,  360,  720, 360,  720, 360,  720, 360,  720, NULL, NULL, NULL, NULL), 
('2020-12-27', '2020-12-31', 480, 1020, 480, 1020, 480, 1020, 480, 1020, 480, 1020, NULL, NULL, 360, 720);

每个数值对应于以分钟为单位的开始或结束(即 360 -> 6:00 AM,1320 -> 10:00 PM;1320 和 360 之间的差异是 960 分钟,是设备上的有效可用性例如一天)。 “期间”表中的每条记录都不会跨越 2 个月或更长时间:只是 1 个月的一部分。 鉴于上述数据集,我想得到以下结果:

(Period, minutes_of availability)

    ('2020-10', 4800), <---- 1 Monday = 960 minutes + 1 Tuesday = 960 minuntes + 1 Wednesday = 960 minutes .....
    ('2020-11', 20160), <---- 5 Monday = 4800 minutes + 4 Tuesday = 3840 minutes + 4 Wednesday = 3840 minutes .....
    ('2020-12', 17220), <---- 3 Monday (until 23 December and before today) = 2880 minutes + 4 (until 23 December and before today) ..... 24 December ha a different availability, after 27 too

此外,计算应该在“当前日期”停止,所以我不想计算整个日历。 有人可以帮我解决这个问题吗? 我的数据库引擎是 SQL Server。

结束

【问题讨论】:

  • 乐于助人,您研究过、尝试过什么并坚持不懈?
  • 仅供参考的数据库有列,而不是字段。
  • 发布 DDL,而不是您的表格的文字描述。与其强迫每个人猜测你是如何得出“1 个星期一 = 960 分钟 + ...”的,不如写出你使用的实际公式和所用值的来源。对你来说这似乎很明显,但对其他人来说可能不是。而且您似乎假设一行的日期不超过一个月的界限。这是一个安全的假设吗?该表是否有约束来保证它?如果不是,您仍然认为这是一个安全的假设吗?
  • “sysdate”是指SysDateTime吗?这是否意味着您希望计算运行到当前时间,而不仅仅是日期?
  • @Dale K,我不知道如何执行这样的“选择”。

标签: sql sql-server tsql


【解决方案1】:

你可以试试下面的查询,

SELECT convert(varchar(7), gcp_start, 126) as month,
sum(
(datediff(day, -7, gcp_end)/7 - datediff(day, -6, gcp_start)/7) *  (isnull(gcp_monend, 0) - isnull(gcp_monstart, 0))
+ (datediff(day, -6, gcp_end)/7 - datediff(day, -5, gcp_start)/7) * (isnull(gcp_tuesend, 0) - isnull(gcp_tuesstart, 0))
+ (datediff(day, -5, gcp_end)/7 - datediff(day, -4, gcp_start)/7 )*  (isnull(gcp_wedend, 0) - isnull(gcp_wedstart, 0))
+ (datediff(day, -4, gcp_end)/7 - datediff(day, -3, gcp_start)/7) *  (isnull(gcp_thursend, 0) - isnull(gcp_thursstart, 0))
+ (datediff(day, -3, gcp_end)/7 - datediff(day, -2, gcp_start)/7) *  (isnull(gcp_friend, 0) - isnull(gcp_fristart, 0))
+ (datediff(day, -2, gcp_end)/7 - datediff(day, -1, gcp_start)/7) *   (isnull(gcp_satend, 0) - isnull(gcp_satstart, 0))
+ (datediff(day, -1, gcp_end)/7 - datediff(day, 0, gcp_start)/7) *  (isnull(gcp_sunend, 0) - isnull(gcp_sunstart, 0))
) as minutes_of_availability
from period
where gcp_end < getdate()
group by convert(varchar(7), gcp_start, 126);

SQL 小提琴链接: http://sqlfiddle.com/#!18/e6c541/30


注意:

  1. 要获取月份和年份部分,请使用post 中提到的方法。
  2. 要查找开始日期和结束日期之间的工作日数,请参阅this
  3. 假设,gcp_end 将与gcp_start 在同一个月下降

更新: 修改了 sql 以包含日期范围之间的记录。

SELECT convert(varchar(7), gcp_start, 126) as month,
sum(
(  datediff(day, -7, iif(gcp_end < getdate(), gcp_end, getdate()))/7 - datediff(day, -6, gcp_start)/7) * (isnull(gcp_monend, 0) - isnull(gcp_monstart, 0))
+ (datediff(day, -6, iif(gcp_end < getdate(), gcp_end, getdate()))/7 - datediff(day, -5, gcp_start)/7) * (isnull(gcp_tuesend, 0) - isnull(gcp_tuesstart, 0))
+ (datediff(day, -5, iif(gcp_end < getdate(), gcp_end, getdate()))/7 - datediff(day, -4, gcp_start)/7 )* (isnull(gcp_wedend, 0) - isnull(gcp_wedstart, 0))
+ (datediff(day, -4, iif(gcp_end < getdate(), gcp_end, getdate()))/7 - datediff(day, -3, gcp_start)/7) *  (isnull(gcp_thursend, 0) - isnull(gcp_thursstart, 0))
+ (datediff(day, -3, iif(gcp_end < getdate(), gcp_end, getdate()))/7 - datediff(day, -2, gcp_start)/7) *  (isnull(gcp_friend, 0) - isnull(gcp_fristart, 0))
+ (datediff(day, -2, iif(gcp_end < getdate(), gcp_end, getdate()))/7 - datediff(day, -1, gcp_start)/7) *   (isnull(gcp_satend, 0) - isnull(gcp_satstart, 0))
+ (datediff(day, -1, iif(gcp_end < getdate(), gcp_end, getdate()))/7 - datediff(day, 0, gcp_start)/7) *  (isnull(gcp_sunend, 0) - isnull(gcp_sunstart, 0))
) as minutes_of_availability
from period
where gcp_start <= getdate()
group by convert(varchar(7), gcp_start, 126);

SQL 小提琴链接: http://sqlfiddle.com/#!18/e6c541/30

【讨论】:

  • 除非我遗漏了一些东西,否则它可以简单得多?即GCP_MONEND - GCP_MONSTART ...
  • @Dale K,正确的公式不是那么简单,我需要测试一下,但是 Prasanna 建议我的非常接近我的需要。谢谢。
  • @Prasanna,谢谢,它可以按我的需要工作,但效率为 90% :-) ...似乎直到 getdate() 大于或等于 gcp_end 才考虑记录,所以,今天是 12 月 27 日,是星期天,所以我的表中有一个空值,但是如果我为星期天放置一些有效值,它们直到 12 月 30 日(gcp_end)才会被考虑,这不是我需要的。我正在尝试分析您的代码以改进它(尽我所能),因为我每天(甚至在我的记录日期范围内)都需要我的设备可用性。再次感谢。
  • @over,请检查这个sqlfiddle.com/#!18/afc810/2是不是你需要的?我会检查极端情况并更新答案。谢谢
  • @Prasanna,抱歉耽搁了,您调整的解决方案正是我所需要的。再次感谢。我将更好地记录这篇文章(我将从您在 sqlfiddle 中的语句中复制一些内容)以供将来使用。再见。
猜你喜欢
  • 2016-07-27
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
  • 2019-05-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多