代码之家  ›  专栏  ›  技术社区  ›  Dante

请参阅ORA-00905:WHERE子句中的CASE语句导致缺少关键字错误

  •  0
  • Dante  · 技术社区  · 2 年前

    我看到一个 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 无效的 错误又回来了。

    1 回复  |  直到 2 年前
        1
  •  1
  •   MT0    2 年前

    绑定变量不是替换变量;它们不会被输入的文本替换,因此无法使用 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;