我有一个名为“订阅”的表格,如下所示。
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
我正试图以不同的方式执行以下查询。
第一个查询返回一行:
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
有人可以帮助我理解第一个和第二个查询之间的区别吗?
答案 0 :(得分: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
关键部分是您使用格式模型14
转换YYYY
。正如the documentation mentions:
数字元素用前导零填充到宽度 元素允许的最大值。例如,
YYYY
元素 被填充到四位数(长度'9999')
虽然这部分主要讨论的是to_char
,但这同样适用于to_date
。执行to_date('14', 'YYYY')
时,它被解释为to_date('0014', 'YYYY')
。您可以改为使用RRRR
或RR
,因为您只提供了当年的两位数字,其中任何一个都会给您2014
;但最好是明确的。
看起来您也是在插入过程中执行此操作,因为如果到期日期也在41919
,您的第一个查询只会找到记录0014
。
当您使用纪元时间戳转换时,您实际上获得了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
如果您在第一个查询中更改日期字符串或格式模型(现在只能使用,因为Oracle有时太有助于解析这些),您也会看到没有数据:
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
,则不会返回任何行。
答案 1 :(得分:0)
检查通过查询DBMS_Xplan()生成的解释计划的完整输出,它将显示内部使用的值作为评估这些常量的结果。这可能表明存在意外的数据类型转换。