看到 ORA-00905: 由于 WHERE 子句中的 CASE 语句导致缺少关键字错误

Seeing ORA-00905: missing keyword error due to CASE statement in WHERE clause

我在位置看到 ORA-00905: missing keyword at 错误:181,似乎无法弄清楚 SQL(Oracle PL/SQL)有什么问题。

SELECT *
FROM FOO
    WHERE LOCATION = :LOCATION
      AND SAVED_DATE >= CASE WHEN :BEGIN_D IS NULL THEN SAVED_DATE ELSE TIMESTAMP :BEGIN_D END
      AND SAVED_DATE <= CASE WHEN :END_D IS NULL THEN SYSDATE ELSE TIMESTAMP :END_D END
 ORDER BY SAVED_DATE;

我的假设是,如果用户输入是:

:LOCATION = 'new york'
:BEGIN_D = NULL
:END_D = NULL

则查询推导为:

SELECT *
FROM FOO
    WHERE LOCATION = 'new york'
      AND SAVED_DATE >= SAVED_DATE -- This line is ignored
      AND SAVED_DATE <= SYSDATE
 ORDER BY SAVED_DATE;

但是我看到了开头提到的错误。

当输入不是 NULL(例如::BEGIN_D = '2015-12-01 00:01:44')时,我没有看到错误。如果 :BEGIN_D:END_D 之一或两者都是 NULL,则错误返回。

绑定变量不是替换变量;它们不会被您输入的文本替换,因此您不能使用 TIMESTAMP :BEGIN_D。您只想使用 :BEGIN_D 并传入 TIMESTAMP 数据类型。

SELECT *
FROM   FOO
WHERE  LOCATION = :LOCATION
AND    SAVED_DATE >= CASE WHEN :BEGIN_D IS NULL THEN SAVED_DATE ELSE :BEGIN_D END
AND    SAVED_DATE <= CASE WHEN :END_D IS NULL THEN SYSDATE ELSE :END_D END
ORDER BY SAVED_DATE;

您也不需要使用 CASE 表达式:

SELECT *
FROM   FOO
WHERE  LOCATION = :LOCATION
AND    (:BEGIN_D IS NULL OR SAVED_DATE >= :BEGIN_D)
AND    ((:END_D IS NULL AND SAVED_DATE <= SYSDATE) OR SAVED_DATE <= :END_D)
ORDER BY SAVED_DATE;

如果您传递的是字符串值(而不是时间戳),则使用 TO_DATE:

SELECT *
FROM   FOO
WHERE  LOCATION = :LOCATION
AND    (:BEGIN_D IS NULL OR SAVED_DATE >= TO_DATE(:BEGIN_D, 'YYYY-MM-DD HH24:MI:SS'))
AND    ((:END_D IS NULL AND SAVED_DATE <= SYSDATE) OR SAVED_DATE <= TO_DATE(:END_D, 'YYYY-MM-DD HH24:MI:SS'))
ORDER BY SAVED_DATE;