2016-08-04 36 views
0

我正在使用SQL Server 12.0.4213.0並且是高級SQL查詢的新手。SQL解析持續時間字符串到秒

我有一個名爲含有兩種格式之一的時間跨度持續時間一個nvarchar柱:39 Seconds如果持續時間下1分鐘,否則該格式是這樣1 Day 18 Hours 2 Minutes。請注意,每日/每小時/每分鐘/秒可以是單數或複數。在第一種格式中,如果日期爲0,則該日將被省略(與小時相同)。

我需要將持續時間轉換爲表示總秒數的整數。 1 Minute 30 Seconds應該返回90和39 Seconds應該返回39.

我認爲這可以用嵌套的CASE語句來完成。數據集非常大,所以我想確定我正在有效地處理這個問題。任何幫助,將不勝感激。

一種方法我在PowerShell的工作是將持續時間列於空格字符通過所得陣列通過2計數器遞增分裂,環,取array[counter]並且通過array[counter+1]確定的相應秒值相乘,添加產品的總秒數總和。

+0

應該可以使用字符串函數來實現你想要的。但是,爲什麼要避免這種痛苦呢?將時間戳存儲爲...時間戳而不是'nvarchar'。 –

+0

@TimBiegeleisen - 我同意你的觀點,但我不是這個數據庫的管理員,並且嚴格來說是數據的使用者。 – Zachafer

+0

如果只有2分鐘,該怎麼辦?它說0天0小時2分鐘嗎? – scsimon

回答

1

這有點複雜,但並不可怕。解決此問題的方法是從字符串中刪除Day(s),Hours(s),Minute(s),Second(s)標籤,並用一些定界字符串/字符替換它們。

然後您可以使用CTE分割結果值。

然後,您將根據每個零件在分隔字符串中的位置以秒爲單位創建時間跨度。

最後,總結得出的時間跨度部分秒。

編輯:現在定義爲一個功能

像這樣:

CREATE FUNCTION fn_getDurationSeconds(@duration varchar(100)) returns int 
as 
BEGIN 
    DECLARE @durationSeconds INT = 0; 

    with split (duration, part, remainder) as 
    (
     SELECT 
      duration, 
      left(duration, CHARINDEX(':', duration)-1), 
      right(duration, LEN(duration) - CHARINDEX(':', duration)) 
     FROM 
     (
      SELECT 
       REPLACE(
        REPLACE(
         REPLACE(
          REPLACE(
           REPLACE(
            REPLACE(
             CASE WHEN @duration LIKE '% Day' or @duration like '% Days' THEN @Duration + ' 0 Hours 0 Minutes 0 Seconds' 
              WHEN @duration LIKE '% Hour' or @duration like '% Hours' THEN @Duration + ' 0 Minutes 0 Seconds' 
              WHEN @duration LIKE '% Minute'or @duration like '% Minutes' THEN @Duration + ' 0 Seconds' 
              ELSE @Duration 
             END, ' Day', ':'), 
            ' Hour', ':'), 
           ' Minute', ':'), 
          ' Second', ':00'), 
         's', ''), 
        ' ', '') duration 

     ) t 
     union all 
     select 
      duration, 
      left(remainder, CHARINDEX(':', remainder) - 1), 
      right(remainder, LEN(remainder) - CHARINDEX(':', remainder)) 
     from split 
     where CHARINDEX(':', remainder) > 0 
    ) 
    SELECT @durationSeconds = sum(seconds) 
    FROM 
    (
     select 
      duration, 
      CASE row_number() over(partition by duration order by LEN(remainder)) 
       WHEN 4 THEN 24 * 60 * 60 
       WHEN 3 THEN 60 * 60 
       WHEN 2 THEN 60 
       WHEN 1 THEN 1 
      END * CAST(part AS INT) Seconds 
     from split 
    ) t 
    group by duration 
    order by duration 


    RETURN @durationSeconds 
END 
+0

感謝您的回覆。我如何創建一個函數(如calcSecs),我可以通過持續時間並返回int秒?在我的查詢中,我將需要'SELECT ID,DurationSec = SUM(calcSecs([duration])).... GROUP BY ID' – Zachafer

+0

認識到在該代碼中存在一個錯誤(未指定秒時,分鐘計爲秒) .--修正! 我不會推薦在這裏使用一個函數。函數是一個單線程進程,這會減慢你的查詢速度。 如果可能,我的建議是在存儲過程中使用這個邏輯。 – mrtig

+0

爲了防止您無論如何都需要該功能,我更新了我的答案,以形式的功能.. – mrtig

0

另一種選擇是使用substringpatindex和一些公共表表達式來獲得期望的結果:

首先,創建並填充示例表格:(拯救我們在你未來的問題,這一步)

DECLARE @T AS TABLE 
(
    Duration varchar(40), 
    NumberOfSeconds int 
) 

INSERT INTO @T (Duration) VALUES 
('39 Seconds'), 
('2 Minutes 4 Seconds'), 
('1 Hours 7 Minutes 17 Seconds'), 
('3 Days 9 Hour 8 Minutes 25 Seconds') 

然後,使用一個CTE來保存patindex結果每個字。
這個cte只是爲了節省我們一次又一次地寫patindex的必要。 另一個CTE加入這一條,將使用substring提取值爲每個時間部分,採用第一CTE:

;WITH cte1 as 
(
    SELECT *, 
      PATINDEX('%Day%', Duration) As DaysIndex, 
      PATINDEX('%Hour%', Duration) As HoursIndex, 
      PATINDEX('%Minute%', Duration) As MinutesIndex, 
      PATINDEX('%Second%', Duration) As SecondIndex 
    FROM @T 
), cte2 as 
(
SELECT *, 

     CASE WHEN DaysIndex > 0 THEN 
      CAST(SUBSTRING(Duration, 0, DaysIndex) As int) * 60 * 60 * 24 
     ELSE 
      0 
     END As D, 
     CASE WHEN HoursIndex > 0 THEN 
      CAST(
      SUBSTRING(Duration, 
       CASE WHEN DaysIndex > 0 THEN DaysIndex + 4 
       ELSE 0 
       END, 

       CASE WHEN DaysIndex > 0 THEN HoursIndex - DaysIndex - 4 
       ELSE HoursIndex 
       END 
      ) As int) * 60 * 60 
     ELSE 
      0 
     END As H, 
     CASE WHEN MinutesIndex > 0 THEN 
      CAST(
      SUBSTRING(Duration, 
       CASE WHEN HoursIndex > 0 THEN HoursIndex + 5 
       ELSE 0 
       END, 

       CASE WHEN HoursIndex > 0 THEN MinutesIndex - HoursIndex - 5 
       ELSE MinutesIndex 
       END 
      ) As int) * 60 
     ELSE 
      0 
     END As M, 
     CASE WHEN SecondIndex > 0 THEN 
      CAST(
      SUBSTRING(Duration, 
       CASE WHEN MinutesIndex > 0 THEN MinutesIndex + 7 
       ELSE 0 
       END, 

       CASE WHEN MinutesIndex > 0 THEN SecondIndex - MinutesIndex - 7 
       ELSE SecondIndex 
       END 
      ) As int) 
     ELSE 
      0 
     END As S 
FROM cte1 
) 

現在,更新NumberOfSeconds柱:

UPDATE cte2 
SET NumberOfSeconds = D + H + M + S 

驗證更新結果:

SELECT * 
FROM @T 

結果:

Duration         NumberOfSeconds 
---------------------------------------- --------------- 
39 Seconds        39 
2 Minutes 4 Seconds      124 
1 Hours 7 Minutes 17 Seconds    4037 
3 Days 9 Hour 8 Minutes 25 Seconds  292105