我使用Oracle数据库11g版本11.2.0.4.0
执行此查询时:
SELECT
CASE WHEN (DATE '2005-11-25') IN ('25/11/05') THEN
'TRUE'
ELSE
'FALSE'
END
FROM DUAL;FALSE来自Oracle 21.4.1.349 (法语版本),TRUE来自DBeaver 21.1.4.202108020335 (法语版本)。
我知道我将日期与字符串进行比较,所以我认为结果应该是FALSE,但这可能依赖于实现。
在这些情况下,Oracle的回答是如何不同的呢?DBeaver是否在提交请求之前对日期进行预处理?
发布于 2022-01-18 09:37:25
由于要将日期与字符串进行比较,因此将使用会话的NLS设置将字符串隐式转换为日期。这些数据可以从您的地区派生出来,也可以由您的客户显式设置,例如通过首选项。
如果NLS_DATE_FORMAT被设置为'DD/MM/YYYY‘,那么'25/11/05’被转换为0005-11-25,所以比较是假的。如果将其设置为“DD/MM/YY”(或“DD/MM/RR”或“DD/MM/RRRR”),则将其转换为2005-11-25,因此比较是正确的。
您不应该依赖于隐式转换或NLS设置,因为您无法控制运行代码的人的环境。
发布于 2022-01-18 09:37:35
这取决于会话使用的NLS_DATE_FORMAT。
Oracle将隐式地将查询转换为相当于:
SELECT CASE WHEN DATE '2005-11-25' IN (
TO_DATE(
'25/11/05',
(SELECT VALUE FROM NLS_SESSION_PARAMETERS WHERE PARAMETER = 'NLS_DATE_FORMAT')
)
)
THEN 'TRUE'
ELSE 'FALSE'
END
FROM DUAL;由于它依赖于从字符串到日期的隐式转换,因此Oracle将在转换中使用会话的日期格式。
例如:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD/MM/RR';
SELECT CASE WHEN DATE '2005-11-25' IN ('25/11/05')
THEN 'TRUE'
ELSE 'FALSE'
END
FROM DUAL;产出:TRUE
但是:
ALTER SESSION SET NLS_DATE_FORMAT = 'DD/MM/YYYY HH24:MI:SS';
SELECT CASE WHEN DATE '2005-11-25' IN ('25/11/05')
THEN 'TRUE'
ELSE 'FALSE'
END
FROM DUAL;产出:FALSE
您可以理解为什么使用:
SELECT TO_CHAR(CAST('25/11/05' AS DATE), 'YYYY-MM-DD HH24:MI:SS') FROM DUAL;它输出0005-11-25 00:00:00,是第一个世纪,而不是21世纪,因为隐式转换使用DD/MM/YYYY HH24:MI:SS格式模型,并期望有一个4位数的年份,并获得输入05,并假定它是一个正确的值为5 AD,而不是当前世纪的第5年(您可以使用YY格式模型得到该值)。
最好的解决方案是不依赖于隐式字符串到日期转换。
要么使用日期文字:
SELECT CASE WHEN DATE '2005-11-25' IN (DATE '2005-11-25')
THEN 'TRUE'
ELSE 'FALSE'
END
FROM DUAL;或者,为转换提供显式格式模型:
SELECT CASE WHEN DATE '2005-11-25' IN (TO_DATE('25/11/05', 'DD/MM/RR'))
THEN 'TRUE'
ELSE 'FALSE'
END
FROM DUAL;db<>fiddle https://dbfiddle.uk/?rdbms=oracle_21&fiddle=49005d1bb671c324c3819b84a1dd1378
https://stackoverflow.com/questions/70753122
复制相似问题