2017-08-31 286 views
0

我有一個字段指定了將來的時間戳,記錄的到期時間。我希望能夠接受字符串時間戳或表示從現在開始的時間間隔。是否有一些簡單的方法來嘗試將字符串轉換爲間隔,如果成功,則將其添加到now(),否則將其轉換爲時間戳(帶時區)?強制將時間戳或時間間隔字符串轉換爲時間戳

在它被問到之前,是的,我確定我可以用存儲過程執行它,我很好奇我是否可以使用某種類型的COALESCE樣式magick。如果答案是存儲過程,那就這樣吧,我可以寫出這個答案。


編輯:這是我作爲存儲過程的實現。

create or replace function 
    timestamptz_in_or_at(input text) 
    returns timestamptz 
    as $$ 
    begin 
    begin 
     return now() + input::interval; 
    exception when others then 
     return input::timestamptz; 
    end; 
    end; 
$$ language plpgsql 
+2

像這樣的問題是錯誤處理。如果你只是在裏面插入一個強制類型,而且字符串不正確,你會得到一個SQL錯誤。如果您想查看是否可以在不破壞當前事務的情況下進行強制轉換,那麼您可以在SQL中使用保存點,也可以編寫帶有錯誤處理功能的plpgsql函數。兩者都很好。 –

回答

1

我認爲你唯一的機會是驗證的時間間隔字符串的正則表達式,因爲CAST投上無效的字符串錯誤,make_interval還沒有得到的字符串輸入簽名。

區間輸入格式爲known。你可以用postgres_verbose或ISO格式編寫你想要的精度的正則表達式。

例如:

SELECT 
    CASE WHEN your_text_column ~* '^(\d+ (minute|minutes|second|seconds)\ *)+$' 
    THEN now() + your_text_column::interval 
    ELSE your_text_column::timestamptz END 
FROM test; 

在這種情況下,你必須閱讀從表中的文本類型列間隔/時刻字符串。另一方面,當你的輸入字符串來自用戶輸入時,查詢將變得更加複雜。您必須處理試圖優化常量值的規劃器,即使在CASE的錯誤分支中也是如此。爲了防止這種情況,你必須引入揮發性功能到表現之一:

SELECT 
    CAST(
    CASE WHEN ? ~* '^(\d+ (minute|minutes|second|seconds)\ *)+$' 
    THEN CAST(now() + CAST((? || repeat('',(random()*0)::integer)) AS interval) AS text) 
    ELSE ? END 
    AS timestamptz); 

首先,CASE的分支機構必須返還相同種類。間隔和時間戳不兼容,但text是好的。其次,無論哪種情況,其中一個CAST都會失敗,除非您可以將評估推遲到運行階段。

在區間分支中,|| repeat('',(random()*0)::integer沒有給字符串添加任何內容,但引入了波動性並阻止計劃人員評估可能錯誤的區間文本。

外CAST將CASE的ELSE分支的評估推遲到運行時確定該字符串不包含間隔。

+0

謝謝你的努力。我想你已經證實,在所有的實踐中我所希望的是不可能的。我將我的存儲過程添加爲編輯,我認爲它顯示了總體上更簡單。再次感謝! –

+0

我同意,存儲過程是完成此操作的最佳方法。 –