Oracle 查询失败,添加了 COLLATE 子句

Oracle query fails with added COLLATE clause

在 sqlplus 中,此查询有效:

SQL> SELECT DISTINCT
  2  CNTPTY_TYPE
  3  FROM visn_exp.V_IHCVSN_CERT_DEP
  4  WHERE as_of_dt = '08-may-20'
  5  ;

CNTPTY_TYPE
----------------------------------------

Retail
PSE
Non-Financial Corporate
FI

但是这个失败了,整理子句:

SQL> SELECT DISTINCT
  2  CNTPTY_TYPE COLLATE latin1_general_CI_AI AS CNTPTY_TYPE
  3  FROM VISN_EXP.V_IHCVSN_CERT_DEP
  4  WHERE as_of_dt = '08-may-20'
  5  ;
CNTPTY_TYPE COLLATE latin_general_CI_AI AS CNTPTY_TYPE
                    *
ERROR at line 2:
ORA-00923: FROM keyword not found where expected

我应该怎么做才能解决这个问题?

更新:尝试了答案中建议的查询。得到

SQL*另外:12.2.0.1.0 版于 2020 年 5 月 11 日星期一生产 21:03:20

版权所有 (c) 1982、2017,甲骨文。保留所有权利。

输入密码: 上次成功登录时间:2020 年 5 月 11 日星期一 16:51:34 -04:00

连接到: Oracle Database 12c 企业版 12.1.0.2.0 版 - 64 位生产 随着分区,真正的应用集群,自动存储管理,OLAP, 高级分析和真实应用测试选项

SQL> SELECT DISTINCT
  2  CNTPTY_TYPE COLLATE LATIN_AI AS CNTPTY_TYPE
  3  FROM VISN_EXP.V_IHCVSN_CERT_DEP
  4  WHERE as_of_dt = '08-may-20';
CNTPTY_TYPE COLLATE LATIN_AI AS CNTPTY_TYPE
                    *
ERROR at line 2:
ORA-00923: FROM keyword not found where expected

使用归类时,有三个后缀会改变排序和比较的行为。

"_CI" : Case insensitive, but accent sensitive.
"_AI" : Both case and accent insensitive.
"_CS" : Both case and accent sensitive. This is default if no extension is used.

虽然不确定上述 _general 用法的目的。但是,仅使用 LATIN_xx,将 xx 替换为上述任何选项都可以完成您的工作。

检查拉丁语有效 NLS_SORT 值的查询:-

SELECT * 
FROM V$NLS_VALID_VALUES 
WHERE parameter = 'SORT' and value = 'LATIN'; 

附加信息:Collations in Oracle

汇总查询:

SELECT DISTINCT
CNTPTY_TYPE COLLATE LATIN_AI AS CNTPTY_TYPE
FROM VISN_EXP.V_IHCVSN_CERT_DEP
WHERE as_of_dt = '08-may-20';

一元运算符COLLATE是Oracle 12.2才引入的,所以报错是因为你的版本是12.1.

为什么会收到错误消息“FROM 关键字未在预期位置找到”,以及您找到它的确切位置?因为在 Oracle 12.1 中,COLLATE 这个词没有特殊含义。在 SELECT 子句中的列名之后找到它,Oracle 认为它是该列的别名。由于这个别名(无论如何它认为它是一个别名)后面没有逗号用于 select 的附加表达式,它需要关键字 FROM。它找到了 LATIN_AI(或者你最初尝试过的任何东西)并且 那是它抛出错误的地方 - 它期待 FROM 在那个地方。

12.1 中的解决方法?有一个,但它有缺点。 COLLATE 的好处是您可以在查询中指定排序规则,而不会影响整个会话。与在查询中调用 TO_DATE 时使用日期格式模型相同,而无需更改 NLS_DATE_FORMAT.

唉,在 12.1 中,您无法在查询级别控制排序规则;您必须为会话更改它(如果其他查询或您在会话中执行的其他操作需要不同的排序规则,然后将其更改回来)。您可以通过 运行ning

alter session set nls_sort = 'LATIN_AI';

在你运行你的查询之前。

如果在 运行 这个查询之后需要恢复到 "old" nls_sort,你最好知道它是什么,before 你把它改成 'LATIN_AI'。您可以通过 运行 在 之前 上面显示的 alter session 执行以下查询。

select value from v$nls_parameters where parameter = 'NLS_SORT';

然后,在完成查询后,您需要再次 运行 alter session 以将 nls_sort 更改回旧值。

旁注 - 为什么要将日期与 where 子句中的字符串进行比较? (或者 as_of_date 是字符串数据类型——这是一种更糟糕的做法?)