2009-09-06 69 views
0

使用SQL Server 2000如何在SQL中編寫計算查詢?

我的查詢。

SELECT 
    (Format(IIf(CLng(OutTime) > 180000, CDate('18:00:00'), CDate(Format(OutTime, '00:00:00'))) - IIf(CLng(InTime) < 90000, CDate('09:00:00'), CDate(Format(InTime, '00:00:00'))), 'hh:nn:ss')) As WorkTime, 
    (Format(IIf(CLng(InTime) < 90000, CDate('09:00:00') - CDate(Format(InTime, '00:00:00')), 0) + IIf(CLng(OutTime) > 180000, CDate(Format(OutTime, '00:00:00')) - CDate('18:00:00'), 0), 'hh:nn:ss')) As OverTime 
FROM table 

以上查詢是Access查詢,我想要寫在SQL中相同的查詢。

條件。

我想計算在180000之前090000(HH:MM:SS)進入工作時間之前的時間,在180000之後的 090000進入加班時間。

銀泰,Outime數據類型爲varchar在數據庫

是新的SQL Server 2000

如何寫從上述相同的SQL查詢?

+3

1. That * is * SQL。 SQL Server和Access都使用SQL。如果你想鼓勵人們迴應,請重新設置多行格式以便閱讀。 – 2009-09-06 08:56:34

+0

該查詢以何種方式不適合您? – Unsliced 2009-09-06 09:04:51

+0

不接受CLng,CDate。 – Gopal 2009-09-06 09:19:48

回答

0

這裏是直譯查詢TSQL 2000 雖然,它可以改寫爲更好的性能:

Select Convert(char(8), 
      case when DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00' 
       Then Cast('18:00:00' as datetime) 
       Else DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime) 
      End 
      - 
      Case when DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) <'09:00:00' 
       Then Cast('09:00:00' as datetime) 
       Else DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) 
      End, 
      8 
     ) as WorkTime, 
    Convert(char(8), 
      Case when DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) <'09:00:00' 
       Then Cast('09:00:00' as datetime) - 
        DateAdd(Day,-DateDiff(Day, 0, InTime), InTime) 
       Else Cast('00:00:00' as datetime) 
      End 
      + 
      case when DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00' 
       Then DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime) - 
        Cast('18:00:00' as datetime) 
       Else Cast('00:00:00' as datetime) 
      End, 
      8 
     ) as OverTime 
From Table 

後來補充:

如果銀泰和OutTime有一部分時間(日期部分是1900年1月1日),您可以直接使用InTime和OutTime。否則,您必須提取一部分時間從datetime列,如:

DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime) 

(這是隻得到部分時間以最快的方式)

相反的:

DateAdd(Day,-DateDiff(Day, 0, OutTime), OutTime)>'18:00:00' 

您可以使用

Datepart(hh,OutTime)>17 

PS因爲你的時間存儲爲字符串yoiu不需要只獲取時間部分。你可以將它們轉換成日期時間,或者你也可以寫

cast(left(inTime,2) as int) < 9 
+0

@Niikola - 在算術快速溢出錯誤中顯示錯誤,將表達式數據類型轉換爲日期時間 – Gopal 2009-09-06 10:16:15

+0

InTime和OutTime列的數據類型是什麼? – Niikola 2009-09-06 10:59:58

+0

並且它們是否包含日期部分,或者只是時間部分? – Niikola 2009-09-06 11:03:21

0

我不認爲有一個非常容易和簡單的方式來做到這一點 - 最明顯的是因爲在VARCHAR存儲時間值 - 這是真正使這個棘手.....

無論如何,我使用了兩種功能 - 一種dbo.GetSeconds,它將時間值('103500' - > 10:35:00小時)的字符串表示轉換爲秒數,然後是第二種功能dbo.GetOvertime,檢測是否存在是任何加班。

CREATE FUNCTION dbo.GetSeconds(@input varchar(20)) 
RETURNS int 
AS BEGIN 
    DECLARE @Hour INT 
    DECLARE @Minute INT 
    DECLARE @Second INT 

    DECLARE @TotalSeconds INT 

    SET @Hour = CAST(SUBSTRING(@input, 0, LEN(@input)-3) AS INT) 
    SET @Minute = CAST(LEFT(RIGHT(@input, 4), 2) AS INT) 
    SET @Second = CAST(RIGHT(@input, 2) AS INT) 

    SET @TotalSeconds = @Hour * 3600 + @Minute * 60 + @Second 

    RETURN @TotalSeconds 
END 


CREATE FUNCTION dbo.GetOvertime(@fromSeconds INT, @toSeconds INT) 
RETURNS int 
AS BEGIN 
    DECLARE @Overtime INT 

    SET @Overtime = 0 

    IF @fromSeconds < 32400 -- 32400 seconds = 09:00 hours 
    SET @Overtime = @OverTime + (32400 - @fromSeconds) 

    IF @toSeconds > 64800 -- 64800 seconds = 18:00 hours 
    SET @Overtime = @OverTime + (@toSeconds - 64800) 

    RETURN @Overtime 
END 

有了這兩個功能,我可以很容易計算出你在找什麼:

SELECT 
    dbo.GetOvertime(dbo.GetSeconds(InTime), dbo.GetSeconds(OutTime)) 'Overtime', 
    (dbo.GetSeconds(OutTime) - dbo.GetSeconds(InTime) - 
    dbo.GetOvertime(dbo.GetSeconds(InTime), dbo.GetSeconds(OutTime))) 'Worktime', 
FROM YourTable 

這是涉及到一點 - 正如我所說,如果你是在SQL Server上2008年和使用TIME數據類型,事情會變得更容易!

馬克

+0

沉重,因爲你正在使用字符串。 相反Streing操作,您可以使用: SET @Hour = DATEPART(HH,@輸入) SET @Minute = DATEPART(MI,@輸入) SET @Second = DATEPART(SS,@輸入) 雖然未來表達式將返回秒快得多: Datediff(ss,0,DateAdd(Day,-DateDiff(Day,0,@input),@input)) 最後,最終查詢dos不遵循原始邏輯 – Niikola 2009-09-06 10:52:19

+0

抱歉無格式評論。如何在評論中添加換行符? – Niikola 2009-09-06 10:53:22

+0

由於數據的格式爲09:00:00爲「90000」,因此使用DATEPART的此方法將不起作用:消息241,級別16,狀態1,行9 轉換日期和/或轉換失敗來自字符串的時間。 – 2009-09-06 11:26:18

0

你可以使用子和DATEADD轉換的「090000」一個真正的日期時間字段。然後你可以使用CASE和DATEDIFF來拆分工作和加班。最終格式化可以使用CONVERT完成。這裏有一個例子:

select 
    case when outtime-intime > '9:00:00' then '09:00:00' 
    else convert(varchar(30), outtime-intime, 108) 
    end as WorkTime, 
    case when outtime-intime <= '9:00:00' then '00:00:00' 
    else convert(varchar(30), outtime-intime-'9:00:00', 108) 
    end as OverTime 
from (
    select 
    dateadd(hh,cast(substring('090000',1,2) as int),0) + 
    dateadd(mi,cast(substring('090000',3,2) as int),0) + 
    dateadd(ss,cast(substring('090000',5,2) as int),0) as InTime, 
    dateadd(hh,cast(substring('180500',1,2) as int),0) + 
    dateadd(mi,cast(substring('180500',3,2) as int),0) + 
    dateadd(ss,cast(substring('180500',5,2) as int),0) as OutTime 
) vw 

這將打印:

09:00:00 00:05:00 
+0

它不遵循所要求的邏輯。它僅適用於小時,如果延遲一小時,並延遲一小時,它將顯示9小時WorkTime和0 OverTime,而原始顯示將顯示8小時WT和1小時OT – Niikola 2009-09-06 10:45:14

+0

您是什麼意思,只用幾個小時?這個例子實際上在幾分鐘內。這個問題將前9個小時統計爲工作時間,而不僅僅是前8個(他必須在Elbonia工作) – Andomar 2009-09-06 11:29:38

+0

我的意思是,它只在你編輯你的文章之前用了幾個小時:p 這部分代碼效率極低: dateadd(hh,cast(substring('090000',1,2)as int),0)+ dateadd(mi,cast(substring('090000',3,2)as int),0)+ DATEADD(SS,投(子( '090000',5,2)爲INT),0) 可以使用 CAST('09:00' 作爲DATETIME) – Niikola 2009-09-06 11:42:49

0

這裏是SQL Server 2000的代碼2005+能做到這一點,而無需使用交叉連接的子查詢。

Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome, 
     DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime 
From (  
Select outTime-inTime as diff, 
     DateDiff(mi,t.inTime,'09:00') as bef, 
     DateDiff(mi,'18:00',t.outTime) as aft 
    From Table t) as a 

如果你銀泰和outTime列HASE日期部分也查詢略有不同:

Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome, 
     DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime 
From (  
Select outTime-inTime as diff, 
     DateDiff(mi, DateAdd(Day,-DateDiff(Day, 0, t.inTime), t.inTime),'09:00') as bef, 
     DateDiff(mi,'18:00',DateAdd(Day,-DateDiff(Day, 0, t.OutTime), t.OutTime)) as aft 
    From #t t) as a 
+0

你將得到一個結果爲日期時間。如果你想把它作爲格式化字符串,只需爲'HH:mm'添加Convert(char(5),,8) – Niikola 2009-09-06 11:46:22

+0

我得到的全部是:Msg 8117,Level 16,State 1,Line 4 Operand數據類型varchar對於減算子無效。 – 2009-09-06 13:40:13

+0

問題是:源數據「InTime」和「OutTime」是DATETIME格式的* NOT * - 它是一個VARCHAR字符串,因爲OP提到 – 2009-09-06 13:41:02

0

我錯過了銀泰和outTime的類型。 這裏是varchar的版本

錯過了,但你只需要做Cast(inTime as datetime)。 使用前面2個查詢中的第一個:

Select DateAdd(mi, (Case When bef<0 Then bef else 0 end + Case When aft<0 Then aft else 0 end), diff) as WorkTome, 
     DateAdd(mi, (Case When bef>0 Then bef else 0 end + Case When aft>0 Then aft else 0 end), 0) as OverTime 
    From (  
    Select Cast(t.outTime as datetime)-Cast(t.inTime as datetime) as diff, 
     DateDiff(mi,Cast(t.outTime as datetime),'09:00') as bef, 
     DateDiff(mi,'18:00',Cast(t.outTime as datetime)) as aft 
    From Table t) as a