从sql列计算总工作小时数

从sql列计算总工作小时数,sql,sql-server,Sql,Sql Server,预期结果为3201:20。我用“:”进行了拆分。请提出实现这一目标的最佳方法 DECLARE @tmpTime TABLE ( RowId INT IDENTITY(1, 1), EmployeeId INT, TotalWorkingTime NVARCHAR(10) ); INSERT INTO @tmpTime ( EmployeeId, TotalWorkingTime ) VALUES (1,N'1500:30'), (2,N'1700:50');

预期结果为3201:20。我用“:”进行了拆分。请提出实现这一目标的最佳方法

DECLARE @tmpTime TABLE
(
    RowId INT IDENTITY(1, 1),
    EmployeeId INT,
    TotalWorkingTime NVARCHAR(10)
);

INSERT INTO @tmpTime
(
    EmployeeId, TotalWorkingTime
)
VALUES
(1,N'1500:30'),
(2,N'1700:50');

SELECT SUM(TotalWorkingTime) FROM @tmpTime
您可以尝试使用left()和right()函数在“:”之前和之后查找字符

select 
 concat
 (
  sum(cast(left(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-1) as int)),
  ':',
  case when sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int))>60 then sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int))-60 else sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int)) end
 ) FROM @tmpTime
您可以尝试使用left()和right()函数在“:”之前和之后查找字符

select 
 concat
 (
  sum(cast(left(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-1) as int)),
  ':',
  case when sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int))>60 then sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int))-60 else sum(cast(right(TotalWorkingTime,CHARINDEX(':',TotalWorkingTime)-3) as int)) end
 ) FROM @tmpTime

SQL Server不会关闭超过24小时的时间类型。所以,不要用时间来思考你在做什么。它只是一个时髦的数字字符串表示

因此,您可以将值解析为数字,进行求和,然后重建值:

select (cast(sum(hh) + sum(mm) / 60 as varchar(255)) + ':' +
        right('00' + cast(sum(mm) % 60 as varchar(255)), 2)
       ) as hhmm
from ( VALUES (1,N'1500:30'), (2,N'1700:50') ) t(EmployeeId, TotalWorkingTime) cross apply
     (values (cast(left(TotalWorkingTime, charindex(':', TotalWorkingTime) - 1) as int),
              cast(stuff(TotalWorkingTime, 1, charindex(':', TotalWorkingTime), '') as int)
             )
     ) v(hh, mm)

SQL Server不会关闭超过24小时的时间类型。所以,不要用时间来思考你在做什么。它只是一个时髦的数字字符串表示

因此,您可以将值解析为数字,进行求和,然后重建值:

select (cast(sum(hh) + sum(mm) / 60 as varchar(255)) + ':' +
        right('00' + cast(sum(mm) % 60 as varchar(255)), 2)
       ) as hhmm
from ( VALUES (1,N'1500:30'), (2,N'1700:50') ) t(EmployeeId, TotalWorkingTime) cross apply
     (values (cast(left(TotalWorkingTime, charindex(':', TotalWorkingTime) - 1) as int),
              cast(stuff(TotalWorkingTime, 1, charindex(':', TotalWorkingTime), '') as int)
             )
     ) v(hh, mm)

从@GordonLinoff的回答中可以看出,当使用
VARCHAR
表示真正的持续时间时,您的查询非常复杂。如果以更自然的方式表示数据,则查询会变得更简单。例如,如果将工作时间存储为整数(总分钟),则可以使用中间CTE和两个交叉应用来获得所需的时间:

-- note that TotalWorkingTime is now TotalWorkingTimeMinutes
DECLARE @tmpTime TABLE
(
    RowID INT IDENTITY(1,1),
    EmployeeID INT,
    TotalWorkingTimeMinutes INT
);

-- while I'm using a calculation to show
-- how the minutes get added, this would likely
-- be  done by the application, before it gets
-- sent to the database.
INSERT INTO @tmpTime
(EmployeeID, TotalWorkingTimeMinutes)
VALUES
(1, (1500 * 60) + 30),
(2, (1700 * 60) + 50);

-- I think this intermediate CTE makes things a bit clearer.
-- but of course, you can inline it as well.
WITH SummedMinutesWorked(SummedMinutes) AS
(
    SELECT SUM(TotalWorkingTimeMinutes)
    FROM @tmpTime
)

-- you can use the CROSS APPLY to get the hours,
-- then reference those to get the "remainder minutes"
-- the SELECT has to cast your hours and minutes to a VARCHAR
-- for concatenation
SELECT CAST(H AS VARCHAR(255)) + ':' + CAST(M AS VARCHAR(255))
FROM SummedMinutesWorked
    CROSS APPLY (SELECT SummedMinutes / 60 AS H) AS HoursWorked
    CROSS APPLY (SELECT SummedMinutes - (H * 60) AS M) AS RemainderMinutes

从@GordonLinoff的回答中可以看出,当使用
VARCHAR
表示真正的持续时间时,您的查询非常复杂。如果以更自然的方式表示数据,则查询会变得更简单。例如,如果将工作时间存储为整数(总分钟),则可以使用中间CTE和两个交叉应用来获得所需的时间:

-- note that TotalWorkingTime is now TotalWorkingTimeMinutes
DECLARE @tmpTime TABLE
(
    RowID INT IDENTITY(1,1),
    EmployeeID INT,
    TotalWorkingTimeMinutes INT
);

-- while I'm using a calculation to show
-- how the minutes get added, this would likely
-- be  done by the application, before it gets
-- sent to the database.
INSERT INTO @tmpTime
(EmployeeID, TotalWorkingTimeMinutes)
VALUES
(1, (1500 * 60) + 30),
(2, (1700 * 60) + 50);

-- I think this intermediate CTE makes things a bit clearer.
-- but of course, you can inline it as well.
WITH SummedMinutesWorked(SummedMinutes) AS
(
    SELECT SUM(TotalWorkingTimeMinutes)
    FROM @tmpTime
)

-- you can use the CROSS APPLY to get the hours,
-- then reference those to get the "remainder minutes"
-- the SELECT has to cast your hours and minutes to a VARCHAR
-- for concatenation
SELECT CAST(H AS VARCHAR(255)) + ':' + CAST(M AS VARCHAR(255))
FROM SummedMinutesWorked
    CROSS APPLY (SELECT SummedMinutes / 60 AS H) AS HoursWorked
    CROSS APPLY (SELECT SummedMinutes - (H * 60) AS M) AS RemainderMinutes

你不能
SUM
一个
nvarchar
。SQL Server中的
time
数据类型是介于
00:00:00.0000000
23:59:59.999999
之间的值(尽管闰秒也存在);它的值不能是
24:00
+(当然也不能是
3200:20
。在您的示例中,3200:20的总和是什么?为什么要减少60(分钟)?您使用什么作为表示层?一些应用程序非常乐意提供datetimes作为时间值。例如,在SSRS中(如果我正确地回忆了我的日期数学)日期时间
1900-01-12T17:15:19
可以使用格式
[hh]:mm:ss
表示为值
281:15:19
。如果使用Excel,则它将是
305:15:19
(因为Excel的第0天是
1900-01-00
,而不是
1900-01-01
)。我们在varchar列中有此值。您不能
SUM
nvarchar
time
数据类型在SQL Server中是介于
00:00.0000000
23:59:59.999999
之间的值(尽管闰秒也存在);它不能有
24:00
+(当然不是
3200:20
。您的示例中3200:20的总和是什么?为什么要减少60分钟?您使用什么作为表示层?一些应用程序非常乐意提供日期时间作为时间值。例如,在SSRS中(如果我正确地回忆了日期数学)日期时间
1900-01-12T17:15:19
可以使用格式
[hh]:mm:ss
表示为值
281:15:19
。如果使用Excel,则它将是
305:15:19
(因为Excel的第0天是
1900-01-00
,而不是
1900-01-01
)。我们在varchar列中有此值。此值将返回
3200:80
。一小时内只有60分钟,而不是100分钟。此值将返回
3200:80
。一小时内只有60分钟,而不是100分钟。我们将使用此值作为开箱即用的解决方案。非常好的示例,包含大量注释。非常感谢。扎克。我们将使用此值作为开箱即用的解决方案解决方案。非常好的例子,有很多评论。非常感谢。谢谢扎克。