【问题标题】:Calculate duration based on working time from another table根据另一个表的工作时间计算持续时间
【发布时间】:2022-11-01 23:12:54
【问题描述】:

我有一个表,它注册了商店执行的某些进程的所有步骤,如下所示:

Store Step Timestamp
1 1 2022-10-10 10:00:00.000
1 2 2022-10-10 10:30:00.000
1 3 2022-10-11 09:00:00.000
1 4 2022-10-13 10:00:00.000

还有一个有开店和关店时间的:2

Store Open Close Dayofweek Day
1 08:00:00.000 17:00:00.000 1 monday
1 08:00:00.000 17:00:00.000 2 tuesday
1 null null 3 wednesday
1 09:00:00.000 18:00:00.000 4 thursday
2 09:00:00.000 18:00:00.000 1 monday
2 09:00:00.000 18:00:00.000 2 tuesday
2 09:00:00.000 12:00:00.000 3 wednesday
2 09:00:00.000 18:00:00.000 4 thursday

因此,我需要计算每家商店完成这些步骤所需的时间。结果应该是这样的:

Store Duration(hours)
1 17

obs:7(星期一)+ 9(星期二)+ 0(星期三)+ 1(星期四)= 17

有人知道不使用函数的解决方案吗?

我尝试通过使用连接来做到这一点,但是持续时间(以天为单位)并不总是相同的,我遇到了一些问题。

【问题讨论】:

  • 我不知道您如何得出每日持续时间或表 1 中的步骤与表 2 中的打开/关闭时间之间的关系。添加到您的问题您用来得出每日持续时间的确切方程式。

标签: sql postgresql


【解决方案1】:

这个答案使用 TSQL,而不是 postgres。需要对其进行调整以使用 postgres 来完全回答问题。 因为它确实解决了问题,所以我把它留在这里,以便更熟悉 postgres 的人可以将它用作参考。

这变得非常复杂,因为您基本上需要每天进行日期数学运算,并使用正确的开始/结束时间进行数学运算。

这是一个工作示例,您可以使用它进行测试以使您更接近目标,以及我测试它的数据> 请注意,我更改了您列出的 WeekDay 值以匹配我的 SQL Server 的配置方式。

DECLARE @Steps TABLE (StoreID INT, StepID INT, TimeStamp DATETIME);
INSERT INTO @Steps (StoreID, StepID, TimeStamp) VALUES
(1, 1, '2022-10-10 10:00:00.000'),
(1, 2, '2022-10-10 10:30:00.000'),
(1, 3, '2022-10-11 09:00:00.000'),
(1, 4, '2022-10-13 10:00:00.000'),
(2, 1, '2022-10-10 10:00:00.000'),
(2, 2, '2022-10-10 10:30:00.000'),
(2, 3, '2022-10-10 11:00:00.000'),
(2, 4, '2022-10-10 11:30:00.000');

DECLARE @Stores TABLE (StoreID INT, OpenTime TIME, CloseTime TIME, Dayofweek TINYINT, Day NVARCHAR(20));
INSERT INTO @Stores (StoreID, OpenTime, CloseTime, Dayofweek, Day) VALUES
(1, '08:00:00.000','17:00:00.000', 2, 'monday'),
(1, '08:00:00.000','17:00:00.000', 3, 'tuesday'),
(1,  NULL,           NULL        , 4, 'wednesday'),
(1, '09:00:00.000','18:00:00.000', 5, 'thursday'),
(2, '09:00:00.000','18:00:00.000', 2, 'monday'),
(2, '09:00:00.000','18:00:00.000', 3, 'tuesday'),
(2, '09:00:00.000','12:00:00.000', 4, 'wednesday'),
(2, '09:00:00.000','18:00:00.000', 5, 'thursday');
;WITH stepStartEnd AS (
SELECT StoreID, MIN(TimeStamp) AS StartDateTime, MAX(TimeStamp) AS FinishDateTime
  FROM @Steps s
 GROUP BY StoreID
), StepDays AS (
SELECT StoreID, StartDateTime, FinishDateTime, DATEPART(WEEKDAY,StartDateTime) AS Day, 1 AS iSStart
  FROM stepStartEnd
 UNION ALL
SELECT StoreID, DATEADD(DAY,1,StartDateTime), FinishDateTime, DATEPART(WEEKDAY,DATEADD(DAY,1,StartDateTime)) AS Day, 0
  FROM StepDays
 WHERE StepDays.FinishDateTime > StartDateTime
   AND CAST(StartDateTime AS DATE) <> CAST(StepDays.FinishDateTime AS DATE)
), WorkHours AS (
SELECT s.StoreID, sd.StartDateTime, sd.FinishDateTime,
CASE WHEN CAST(CONVERT(VARCHAR,sd.StartDateTime,111)+' '+CONVERT(VARCHAR,OpenTime,108) AS DATETIME) < sd.FinishDateTime AND iSStart = 1 THEN 
CAST(CONVERT(VARCHAR,sd.StartDateTime,111)+' '+CONVERT(VARCHAR,sd.StartDateTime,108) AS DATETIME)
ELSE CAST(CONVERT(VARCHAR,sd.StartDateTime,111)+' '+CONVERT(VARCHAR,s.OpenTime,108) AS DATETIME) END AS TodaysStartTime,
CASE WHEN CAST(CONVERT(VARCHAR,sd.StartDateTime,111)+' '+CONVERT(VARCHAR,s.CloseTime,108) AS DATETIME) > sd.FinishDateTime THEN 
CAST(CONVERT(VARCHAR,sd.StartDateTime,111)+' '+CONVERT(VARCHAR,sd.FinishDateTime,108) AS DATETIME)
ELSE CAST(CONVERT(VARCHAR,sd.StartDateTime,111)+' '+CONVERT(VARCHAR,s.CloseTime,108) AS DATETIME) END AS TodaysEndTime
  FROM StepDays sd
    INNER JOIN @stores s
      ON SD.StoreID = s.StoreID
      AND sd.Day = s.Dayofweek
)

SELECT StoreID, SUM(DATEDIFF(MINUTE,TodaysStartTime, TodaysEndTime)/60.0) AS WorkHours
  FROM WorkHours
 GROUP BY StoreID
StoreID WorkHours
-----------------
1       17.000000
2       1.500000

【讨论】:

  • 这是不正确的答案。 OP 与 Postgres 一起使用,上面使用的是 T-SQL,并且与 Postgres 不兼容。
  • @AdrianKlaver我确实错过了OP将其标记为postgres,我不熟悉那种语法。也许您可以使用 TSQL 答案来生成 postgres 示例?
  • 然后你需要删除答案。
猜你喜欢
  • 2021-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-22
  • 1970-01-01
  • 2011-07-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多