2014-01-13 113 views
1

我有一個名爲「subscription」的表,如下所示。oracle查詢中'to_date'和'long to date'之間的結果混淆

desc subscription; 

Name     Null  Type  
--------------------- -------- ---------- 
SUBSCRIPTION_ID  NOT NULL NUMBER(38) 
EXPIRATIONDATE     DATE` 

並輸出查詢如下。

SELECT 
    subscription_id, 
    expirationdate 
FROM subscription 
WHERE subscription_id = 41919; 

SUBSCRIPTION_ID  EXPIRATIONDATE   
---------------------- ------------------------- 
41919     18-JAN-14 13:45:56 

而我試圖以不同的方式執行以下查詢。

1查詢返回一行:

SELECT s.subscription_id 
    FROM subscription$active s 
WHERE s.expirationdate - (116/24) 
     BETWEEN TO_DATE('13-JAN-14 11:38:22', 'dd/mm/yyyy hh24:mi:ss') 
      AND TO_DATE('13-JAN-14 18:30:00', 'dd/mm/yyyy hh24:mi:ss') 
    AND s.subscription_id = 41919; 

SUBSCRIPTION_ID   
---------------------- 
41919 

第二查詢不返回行:

SELECT s.subscription_id 
    FROM subscription$active s 
WHERE s.expirationdate - (116/24) 
     BETWEEN (trunc(1389613102220/(1000), 0)/(24 * 60 * 60)) 
       + to_date('01/01/1970', 'mm/dd/yyyy') 
      AND (trunc(1389637800000/(1000), 0)/(24 * 60 * 60)) 
       + to_date('01/01/1970', 'mm/dd/yyyy') 
    AND s.subscription_id = 41919; 

SUBSCRIPTION_ID 
---------------- 

這裏既有where子句相同以上。第一個嘗試使用「to_date」,第二個轉換「long to date」。但是當我看到輸出時,第一個返回一行,第二個不返回任何結果。 我無法找出這裏'長久以來'的轉換有什麼不同。

長到最新的轉換也是正確的。
select (trunc(1389613102220/(1000), 0)/(24 * 60 * 60)) + to_date('01/01/1970','mm/dd/yyyy') from dual

輸出:
13-JAN-14 11:38:22

而且

select (trunc(1389637800000/(1000), 0)/(24 * 60 * 60)) + to_date('01/01/1970','mm/dd/yyyy') from dual

輸出:
13-JAN-14 18:30:00

有人可以幫助我理解不同第一次和第二次查詢之間的差異?

回答

3

這個問題並不是你的基於時代的查詢,它是你的表中的數據(在某種程度上,你構建非時代版本的日期的方式)。您正在使用2位數年份和4位數字格式掩碼。當您在過濾器中使用to_date時,實際上使用的是0014,而不是2014;你可以看到,只是結果與全四位數年份轉換的字符串值,但顯示:

select to_char(to_date('13-JAN-14 11:38:22', 'dd/mm/yyyy hh24:mi:ss'), 
    'YYYY-MM-DD HH24:MI:SS') as test_date 
from dual; 

TEST_DATE   
------------------- 
0014-01-13 11:38:22 

的關鍵部分是,你正在使用的格式模型YYYY轉換14。作爲the documentation mentions

數字元素被填充有前導零以允許該元素的 最大值的寬度。例如,YYYY元件 被填充到四個數字

雖然這(的「9999」的長度)在該節的大多談論to_char,這同樣適用於to_date。當你做to_date('14', 'YYYY')時,它被解釋爲to_date('0014', 'YYYY')。您可以使用RRRRRR,因爲您只提供一年中的兩位數字,其中任何一個都會給您2014;但最好是明確的。

看起來你在插入過程中也是這麼做的,因爲如果第一個查詢的到期日期也在0014之內,那麼你的第一個查詢只能找到記錄41919

當你使用紀元時間戳轉換時,你實際上獲得了2014,所以你的記錄真的不在該範圍內。

要確認,指定與全年的格式模型在初始查詢:

select subscription_id, 
    to_char(expirationdate, 'YYYY-MM-DD HH24:MI:SS') as expirationdate 
from subscription 
where subscription_id = 41919; 

SUBSCRIPTION_ID EXPIRATIONDATE  
--------------- ------------------- 
      41919 0014-01-18 13:45:56 

你也看不到任何數據,如果你更改日期字符串或格式化模型(只作品現在因爲甲骨文是有時太有幫助解析這些),在第一個查詢:

select s.subscription_id from subscription s 
where s.expirationdate - (116/24) between TO_DATE('13-JAN-14 11:38:22', 
    'dd-mon-rr hh24:mi:ss') 
    and TO_DATE('13-JAN-14 18:30:00', 'dd-mon-rr hh24:mi:ss') 
and s.subscription_id=41919; 

...這將不返回行,如果表日期爲0014

+0

是的。你是對的。問題是因爲我插入的2位數年份。謝謝你的幫助。 – vijayashankard

0

檢查通過查詢DBMS_Xplan()生成的解釋計劃的完整輸出,並且它將顯示由於評估這些常量而在內部使用的值。這可能表明存在意外的數據類型轉換。