【问题标题】:time not shown in proper format ; extra unit时间未以正确格式显示;额外单位
【发布时间】:2014-02-13 20:49:04
【问题描述】:

如果总工作时间大于 08:00,则成功计算一个人已经工作和加班的总时间,但如果不大于该时间,则该人未在加班列中工作的持续时间,但现在加班列应显示该时间以适当的否定格式,例如如果某人从 14:49 工作到 15:20 比 Overtime 栏应该显示 -00:29 但我的栏显示它像这样 23:29,为什么 23: 而不是 00: ?我怎样才能得到正确的时间?

代码

with times as (
SELECT    t1.EmplID
        , t3.EmplName
        , min(t1.RecTime) AS InTime
        , max(t2.RecTime) AS [TimeOut]
        , cast(min(t1.RecTime) as datetime) AS InTimeSub
        , cast(max(t2.RecTime) as datetime) AS TimeOutSub
        , t1.RecDate AS [DateVisited]
FROM  AtdRecord t1 
INNER JOIN 
      AtdRecord t2 
ON    t1.EmplID = t2.EmplID 
AND   t1.RecDate = t2.RecDate
AND   t1.RecTime < t2.RecTime
inner join 
      HrEmployee t3 
ON    t3.EmplID = t1.EmplID 
group by 
          t1.EmplID
        , t3.EmplName
        , t1.RecDate
)
SELECT EmplID
,EmplName
,InTime
,[TimeOut]
,[DateVisited]
,convert(char(5),cast([TimeOutSub] - InTimeSub as time), 108) totaltime
,convert(char(5), case when TimeOutSub - InTimeSub >= '08:01' then 
cast(TimeOutSub - dateadd(hour, 8, InTimeSub) as time) else cast(8 - (TimeOutSub - InTimeSub) as time) end, 108) as overtime
FROM times

【问题讨论】:

  • 如果你能使用一些标点符号和礼貌就好了。
  • 好的先生,下次我会尽力的:)正如你所说:)

标签: sql tsql datetime sql-server-2008-r2 sql-server-2012


【解决方案1】:

原因是因为数据类型TIME 应该存储时间,而-00:29 不是时间(即这个时间永远不会在一天内发生)。

您正在尝试以用于显示时间的常用格式显示显示持续时间,这与显示时间不同。这可以通过运行相当简单地显示:

SELECT CAST('-00:27' AS TIME)

哪个会引发错误:

从字符串转换日期和/或时间时转换失败。

之所以显示这个是因为00:00 减去00:31 是前一天的23:29

我个人会使用分钟来完成所有计算,例如

SELECT  StartTime,
        EndTime,
        HoursWorked = DATEDIFF(MINUTE, StartTime, EndTime) / 60.0,
        MinutesOver = 480 - DATEDIFF(MINUTE, StartTime, EndTime)
FROM    (VALUES 
            (CAST('06:50' AS TIME), CAST('15:20' AS TIME)),
            (CAST('07:50' AS TIME), CAST('15:20' AS TIME))
        ) t (StartTime, EndTime);

这给出了:

StartTime | EndTime  | HoursWorked | MinutesOver
----------+----------+-------------+------------
06:50:00  | 15:20:00 |     8.5     |    -30
07:50:00  | 15:20:00 |     7.5     |     30

然后您可以在表示层中应用任何格式。


Aaron Bertrand 在一篇关于Choosing the wrong Data Type 的文章中确实提到了这一点。它指出:

使用 TIME 存储持续时间

使用 SQL Server 2008,将持续时间存储在使用新 TIME 数据类型定义的列中可能很诱人。这种数据类型并不意味着存储持续时间,而是实际上是一个时间点。在这里尝试存储持续时间的一个问题是,当您的持续时间超过 24 小时时会发生什么?将“持续时间”存储在两列 - StartTime 和 EndTime 中会更有用。您可以添加可以计算的第三列,以分钟或秒或任何有意义的方式计算持续时间。如果您有理由相信持续时间将始终小于 24 小时并且不会跨越任何午夜界限,那么您对 ​​StartTime 和 EndTime 列的选择可能是 TIME,但更有可能它们应该是 SMALLDATETIME 或 DATETIME。


附录

我会对您的代码做的第一件事是删除 CTE 中的内部联接:

FROM    AtdRecord t1 
        INNER JOIN AtdRecord t2 
            ON t1.EmplID = t2.EmplID 
            AND t1.RecDate = t2.RecDate
            AND t1.RecTime < t2.RecTime

这是没有意义的,它所做的只是确保每个员工每天有不止一个记录,这将更好地通过有条款来实现。我也会give your tables meaningful aliases,实际上并不是那么需要使用 2 个表,但是当您有很多表时使用 t1、t2、t3 等会很快变得混乱。所以你的查询变成了:

WITH Times AS
(   SELECT  emp.EmplID, 
            emp.EmplName,
            InTime = MIN(atd.RecTime),
            OutTime = MAX(atd.RecTime),
            TimeWorked = DATEDIFF(MINUTE, MIN(atd.RecTime), MAX(atd.RecTime)),
            OverTime = DATEDIFF(MINUTE, MIN(atd.RecTime), MAX(atd.RecTime)) - 480,
            [DateVisited] = atd.RecDate
    FROM    AtdRecord atd 
            INNER JOIN HrEmployee emp 
                ON atd.EmplID = emp.EmplID 
    GROUP BY emp.EmplID, emp.EmplName, atd.RecDate
    HAVING COUNT(atd.RecTime) > 1
)
SELECT  t.EmplID,
        t.EmplName,
        t.InTime,
        t.OutTime,
        t.DateVisited,
        t.TimeWorked,
        OverTime,
        FormattedTimeWorked = CONVERT(CHAR(5), DATEADD(MINUTE, t.TimeWorked, 0), 8),
        FormattedOverTime = CASE WHEN t.OverTime < 0 THEN '-' ELSE '' END +
                                CONVERT(CHAR(5), DATEADD(MINUTE, ABS(t.OverTime), 0), 8)
FROM    Times t;

Simplified Example on SQL Fiddle

【讨论】:

  • 伟大的先生,太棒了,但您能编辑我的代码以显示我想要显示的内容吗?我会追加 - 符号作为字符但时间?
  • 至少有一种方法可以显示一个人没有工作的时间,这会很有帮助,我会附加 - 稍后签名
  • 你是我的爱,先生,太棒了,爱因斯坦,你是 :)
【解决方案2】:

因为你要减去日期。

January 14th, 14:49 - January 14th, 15:20January 13th, 23:29。仔细想想还是有道理的。

改用SUBTIME()

SELECT SUBTIME('14:49', '15:20'); -> '-00:31:00'

编辑:

SUBTIME() 在 SQL-Server 中不可用。我的错。但是对于遇到这个问题的人来说,它可能很有用,所以我把它留在这里。

【讨论】:

  • SUBTIME 是一个 MySQL 函数。 SQL Server 中没有等价物。
  • @Evilrising 要成为一个分心者:您的问题是“为什么是 23:而不是 00:”而不是“您能提供我正确的方法吗?” ;-)
猜你喜欢
  • 1970-01-01
  • 2020-03-30
  • 2019-10-15
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多