2015-10-09 51 views
2

我有ViewSQL名称为vw_Rept_Attend和列名在HH返回大于24小时:mm:ss格式在SQL Server 2008

UserID (int),WorkHrs (varchar),ExtraHrs varchar(), AtnDate (datetime), EmpName (varchar), 
EmpType (varchar), UserName (varchar),Role (varchar) 

WorkHrs实际工作和ExtraHrs

等什么我这样做是

我存储在WorkHrs员工的每日工作时间和ExtraHrs额外的小时,然后我显示出席总结通过过滤器提供的两个日期之间RY报告,

很明显,我做的最大的事情与你的专家建议,申请将小数据和客户端的测试工作正常,我得到了我没有在那个时候考虑的一个问题

问题描述

每一个员工都有工件9小时,每天(每天工作时间)

工作时间(登录时间)

加班(每天工作时间 - 工作时间)

如果员工工作6 hours所以他额外的时间将是-3 hours负的,因为少工作时间比需要的时间和我这个c#声明

wrktime= workinghrs.Subtract(Convert.ToDateTime(time).TimeOfDay); 
TimeSpan Daily_work = new TimeSpan(9, 0, 0); 
TimeSpan exthrs = Convert.ToDateTime(wrktime).TimeOfDay.Subtract(Daily_work); 
得到这个结果

,这会给我负当任何一个工作少于9 hours

因此,如果用户对300 days每天-3 hours添加到database结果将是这样做为300 days

我阅读使用以下sqlprocedure对水晶报表

ALTER PROCEDURE [dbo].[sp_Rpt_Emps_Attnd] 
    @strt date, 
    @end date 
AS 

    begin 
    with cte 
as 
(select UserID, 
      WorkHrs, 
     case when left(ExtraHrs,1)='-' then -1 else 1 end as multiply, 
      right(ExtraHrs,8) as timestring, 
      --get hours in seconds: 
      DATEPART(HOUR,right(ExtraHrs,8)) * 3600 AS h_in_s, 
      --get minutes in seconds: 
      DATEPART(MINUTE,right(ExtraHrs,8)) * 60 AS m_in_s, 
      --get seconds: 
      DATEPART(SECOND,right(ExtraHrs,8)) AS s,AtnDate,EmpName,EmpType, 
      UserName, Role,StartDate,EndDate 

    from  vw_Rept_Attend 
) 

select UserID,dbo.udfTimeSpanFromSeconds(Sum(Left(workhrs,2) * 3600 + substring(Convert(varchar(8),workhrs), 4,2) * 60 + substring(Convert(varchar(8),workhrs), 7,2))) as WorkHrs , 
case when sum((c.h_in_s + c.m_in_s + c.s) * multiply) < 0 
      then '-' + CONVERT(varchar,DATEADD(s,ABS(sum((c.h_in_s + c.m_in_s + c.s) * multiply)),0),114) 

      else CONVERT(varchar,DATEADD(s,sum((c.h_in_s + c.m_in_s + c.s) * multiply),0),114) 
     end as ExtraHrs ,EmpName,EmpType,UserName, Role,convert(VARCHAR(10),StartDate,105) as StartDate,convert(VARCHAR(10),EndDate,105) as EndDate 

from cte c where convert(date,AtnDate) between @strt and @end 
group by UserID,EmpName,EmpType,UserName, Role,StartDate,EndDate 
    Order by UserID 
    end 

和功能显示的计算日期之间的所有WorkHrs的总和作为

ALTER FUNCTION udfTimeSpanFromSeconds(
     @sec INT 
    ) 
    RETURNS VARCHAR(15) 
    AS 
    BEGIN 

RETURN 
    CONVERT(VARCHAR(10), (@sec/3600)) + ':' + 
    RIGHT('0' + CONVERT(VARCHAR(2), ((@sec % 3600)/60)), 2) + ':' + 
    RIGHT('0' + CONVERT(VARCHAR(2), (@sec % 60)), 2) 
END 

我是从把所有这个纪录我stackHow to format time from dd:hh:mm:ss to only hh:mm:ss in SQL server?

但是th这是stored procedure一部分我提到上面即

case when left(ExtraHrs,1)='-' then -1 else 1 end as multiply, 
      right(ExtraHrs,8) as timestring, 
      --get hours in seconds: 
      DATEPART(HOUR,right(ExtraHrs,8)) * 3600 AS h_in_s, 
      --get minutes in seconds: 
      DATEPART(MINUTE,right(ExtraHrs,8)) * 60 AS m_in_s, 
      --get seconds: 
      DATEPART(SECOND,right(ExtraHrs,8)) AS s 

计算ExtHrs总和电子部分只支持24 hours例如,如果结果是27 hours然后它显示3 hours,如果它是-56 hours然后它显示-8 hours

我使用SQL Server 2008,

我认为足够的描述来理解,但如果你们中的任何人不明白,那么请免费要求我分享代码或我使用的任何逻辑。

您的帮助将不胜感激,

在此先感谢。

编辑:

这个问题What is the correct SQL type to store a .Net Timespan with values > 24:00:00?是完全不同的,因为我不是问哪个datatype我应该使用

这里的应用程序可以获取负时间值,例如,-3小时,我说得很清楚,并timespan数据类型不接受负号。

现在我觉得应该清除

更新 在我的数据库,它看起来像

enter image description here

这样计算后ExtHrs应该是-31:50:46但它显示-7:50:46

我认为这是因为不支持大于24 hours

+0

你能抛出一些样本数据,比如只有Extrahr和workhr数据以及你期望的输出吗? – KumarHarsh

+0

@KumarHarsh,请参阅我的编辑 – Waqas

回答

1

顺便说一句,在你使用的proc以及数据类型中有太多的技术缺陷。真正的问题在这里。

  1. 在你的proc中,你可以把第一个CTE本身的日期条件放在哪里。
  2. 如果可能的话,你可以在第二个表格中存储extrahour。这意味着Extrahours是int或者bigint.like -1000或者1000.varchar永远不会解决你的问题。它会以很快的速度为你节省很多转换。
  3. 在组中使用如此之多的列本身是错误的方法,特别是在组中使用varchar列。您应该使用组中的键列,然后再与表连接以获得结果集中的其他列。

与您的示例数据我得到-29:-51:-30.0而不是-31:50:46。 做这种方式,

DECLARE @t TABLE (ExtraHrs VARCHAR(20)) 

INSERT INTO @t 
VALUES ('00:59:38') 
    ,('-03:59:37') 
    ,('-08:59:39') 
    ,('-08:52:36') 
    ,('-08:59:16'); 

WITH cte 
AS (
    SELECT ExtraHrs 
     ,CASE 
      WHEN left(ExtraHrs, 1) = '-' 
       THEN - 1 
      ELSE 1 
      END AS multiply 
     ,right(ExtraHrs, 8) AS timestring 
     , 
     --get hours in seconds: 
     DATEPART(HOUR, right(ExtraHrs, 8)) * 3600 AS h_in_s 
     , 
     --get minutes in seconds: 
     DATEPART(MINUTE, right(ExtraHrs, 8)) * 60 AS m_in_s 
     , 
     --get seconds: 
     DATEPART(SECOND, right(ExtraHrs, 8)) AS s 
    FROM @t 
    ) 
    ,CTE3 
AS (
    SELECT * 
     ,c.h_in_s + c.m_in_s + c.s AddExtra 
    FROM cte c 
    ) 
    ,cte4 
AS (
    SELECT sum(AddExtra * multiply) mn 
    FROM cte3 
    ) 
    ,cte5 
AS (
    SELECT mn/3600 hh 
     ,(mn % 3600)/60 mi 
     ,(mn % 3600.0) % 60 ss 
    FROM cte4 
    ) 
SELECT CASE 
     WHEN hh < 0 
      THEN '-' 
     ELSE '' 
     END 
    ,cast(hh AS VARCHAR) + ':' + cast(mi AS VARCHAR) + ':' + cast(ss AS VARCHAR) 
FROM cte5 

尝试此前导零,

申报@i INT = 5 SELECT REPLICATE( '0',2-LEN(@i))+铸(@i as varchar)

+0

我需要一些时间了解和实施这一点,然后我会更新你,感谢您的时间和精力, – Waqas

+0

其工作正常,但有点问题,我得到“-2:37:12”为“-2:-37:-12.0”,它应该只有“-02:37:12”格式不能与分钟和秒, – Waqas

+0

给我时间。所以只有格式化是一个问题?好 ?也不要使用如此多的cte,因为我有使用。那么多不需要。我纠正格式并发布。 – KumarHarsh

0

ExtraHrs是一个字符串。所以是right(ExtraHrs,8)。那么如何使用日期时间函数(即DATEPART)呢?你不应该这样做。

现在使用什么格式ExtraHrs?你似乎期望有一个可选的(?)符号,后面跟着hh:mm:ss的8个字符。

随着字符串函数和强制转换为数字小值,你会得到:

case when left(extrahrs, 1) = '-' then -1 else 1 end * -- sign 
( 
    (cast(substring(right(extrahrs, 8), 1, 2) as int) * 3600) + -- hours 
    (cast(substring(right(extrahrs, 8), 4, 2) as int) * 60) + -- minutes 
    (cast(substring(right(extrahrs, 8), 7, 2) as int)) + -- seconds 
) as secs 

这使得时间跨度达将近100小时。对于更多的小时,您的格式将不得不更改为hhh:mm:ss或甚至可变长度。

+0

感谢您的关注,先生,SQL不允许我更新过程并抛出“substr不是公认的内置函数名称”的错误任何建议,? – Waqas

+0

嗨瓦卡斯。将其更改为SUBSTRING而不是substr。我编辑了答案,但我正在等待它被同行评审 – TheDanMan

+0

@TheDanMan:谢谢。 –

相关问题