具有日期的 Dbeaver 和 OSD 客户端之间的不同行为

Different behavior between Dbeaver and OSD clients with dates

我使用 Oracle Database 11g 11.2.0.4.0 版

执行此查询时:

SELECT 
    CASE WHEN (DATE '2005-11-25') IN ('25/11/05') THEN
        'TRUE'
    ELSE
        'FALSE'
    END
FROM DUAL;

我从 Oracle SQL Developer 21.4.1.349(法语版)获得 FALSE,从 DBeaver 21.1.4.202108020335(法语版)获得 TRUE

我知道我将日期与字符串进行比较,所以我认为结果应该是 FALSE,但这可能取决于实现。

为什么 Oracle 在这些情况下会做出不同的回答? DBeaver 是否在提交请求之前对日期进行预处理?

因为您将日期与字符串进行比较,所以您使用会话的 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,因此比较为真。

db<>fiddle

您不应依赖隐式转换或 NLS 设置 - 因为您无法控制运行您代码的人的环境。

这取决于 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 并且是 1 世纪,而不是 21 世纪,因为隐式转换使用 DD/MM/YYYY HH24:MI:SS 格式模型并期望 4 位数年份并获得输入 05 并假定它是公元 5 年的正确值,而不是当前世纪的第 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 here