你从十进制(4, 0)到时间的转换是:
DATEADD(MINUTE, (FLOOR([Time] / 100) * 60) + ([Time] % 100), '00:00')
这只是将您的总分钟数添加到 00:00 以获得时间,您的总分钟数计算为 (hours * 60) + minutes where
Hours = FLOOR([Time] / 100)
Minutes = ([Time] % 100)
但是如果为时不晚,您应该完全放弃这种方法。
在 SQL Server 中,很少需要单独存储日期和时间列,最好的方法是使用单个 DATETIME2 列,如果出于任何原因需要单独的列(例如索引),请使用计算列,例如
ALTER TABLE T ADD StartDate AS CAST(StartDateTime AS DATE);
如果您必须至少将两列分开存储,您应该使用TIME 数据类型来存储时间,而不是DECIMAL(4, 0)。解决您的情况的最佳方法是解决实际问题,即不正确的数据类型,而不是您提出的问题。如果你这样做,你会得到如下数据:
Job Op JobDateTime
----------------------------------
1 10 06/01/2015 02:54
1 20 06/01/2015 02:54
1 20 06/01/2015 05:42
1 20 06/01/2015 13:47
1 20 07/01/2015 13:40
1 30 07/01/2015 14:08
1 30 07/01/2015 13:40
1 30 08/01/2015 10:37
1 40 06/01/2015 05:43
等等
那么你的查询就这么简单
SELECT JOb, Op, FirstJob = MIN(JobDateTime), LastJob = MAX(JobDateTime)
FROM T
GROUP BY JOb, Op;
进行此更正的代码是:
ALTER TABLE [YourTable] ADD JobDateTime DATETIME2 NOT NULL;
UPDATE [YourTable]
SET JobDateTime = DATEADD(MINUTE, (FLOOR([Time] / 100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME)));
ALTER TABLE [YourTable] DROP COLUMN [Date];
ALTER TABLE [YourTable] DROP COLUMN [Time];
如果您已经有很多使用这些列的现有代码,您可以使用计算列为您进行计算:
ALTER TABLE YourTable
ADD JobDateTime AS DATEADD(MINUTE, (FLOOR([Time] / 100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME));
例如
CREATE TABLE #T (Job INT, Op INT, [Date] DATE, [Time] DECIMAL(4, 0));
INSERT #T (Job, Op, [Date], [Time])
VALUES
(1, 10, '2015-06-01', 254),
(1, 20, '2015-06-01', 254),
(1, 20, '2015-06-01', 542),
(1, 20, '2015-06-01', 1347),
(1, 20, '2015-07-01', 1340),
(1, 30, '2015-07-01', 1408),
(1, 30, '2015-07-01', 1340),
(1, 30, '2015-08-01', 1037),
(1, 40, '2015-06-01', 543),
(1, 40, '2015-06-01', 1348),
(1, 40, '2015-08-01', 1038),
(1, 50, '2015-07-01', 1219),
(1, 50, '2015-08-01', 1039),
(1, 60, '2015-07-01', 1220),
(1, 60, '2015-10-01', 1054),
(1, 60, '2015-12-01', 859);
ALTER TABLE #T
ADD JobDateTime AS DATEADD(MINUTE, (FLOOR([Time] / 100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME));
SELECT Job,
Op,
FirstJob = MIN(JobDateTime),
LastJob = MAX(JobDateTime)
FROM #T
GROUP BY Job, Op;
如上所述,我建议只将日期和时间作为单列返回,但如果您确实希望它们作为单独的列,那么您至少应该使用 TIME 类型:
无论哪种方式,我都建议返回完整的日期时间,或者至少使用日期和时间列,例如
SELECT Job,
Op,
[Start] = CAST(MIN(JobDateTime) AS DATE),
[End] = CAST(MAX(JobDateTime) AS DATE),
StartTime = CAST(MIN(JobDateTime) AS TIME),
EndTime = CAST(MAX(JobDateTime) AS TIME)
FROM #T
GROUP BY Job, Op;
如果您无法进行任何架构更改,您可以在实际查询中包含公式(在您使用十进制存储时间之后打孔您的 dba):
SELECT Job,
Op,
FirstJob = MIN(DATEADD(MINUTE, (FLOOR([Time] / 100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME))),
LastJob = MAX(DATEADD(MINUTE, (FLOOR([Time] / 100) * 60) + ([Time] % 100), CAST([Date] AS DATETIME)))
FROM #T
GROUP BY Job, Op;