Oracle 11gR2基于函数的索引错误

时间:2014-08-27 08:24:50

标签: sql oracle indexing

我想在一个简单的表上创建一个简单的基于函数的索引,但是我得到了错误。 所以,首先我创建了一个函数

CREATE OR REPLACE FUNCTION promo_function(p_promo_category VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
  RETURN UPPER(p_promo_category);
END promo_function;

然后我会执行此操作,但失败

CREATE INDEX promotions_fbi
          ON SH.PROMOTIONS (promo_function (promo_category));

为什么呢?错误是ORA-00904:" PROMO_FUNCTION":无效的标识符 但该函数在查询中运行良好:

SELECT * 
  FROM sh.sales s,
       sh.promotions p,
       sh.times t
 WHERE s.promo_id = p.promo_id
   AND s.time_id = t.time_id
   AND t.time_id BETWEEN DATE '2000-01-01' AND DATE '2000-03-31'
   AND promo_function(p.promo_category) = 'AD NEWS';

非常感谢!

2 个答案:

答案 0 :(得分:3)

您的代码没有任何内在错误。我可以像这样创建一个基于函数的索引:

SQL> create table promotions (promo_category varchar2(10))
  2  /

Table created.

SQL> CREATE OR REPLACE FUNCTION promo_function
  2      (p_promo_category in VARCHAR2)
  3      RETURN VARCHAR2 DETERMINISTIC 
  4  IS
  5  BEGIN
  6      RETURN UPPER(p_promo_category);
  7  END promo_function;
  8  /

Function created.

SQL> CREATE INDEX promotions_fbi
  2        ON PROMOTIONS (promo_function (promo_category));

Index created.

SQL> 

我的代码和你的代码之间的唯一区别是我没有在CREATE INDEX语句中为表添加前缀。一切都在同一架构中,所以我不需要。

那么,我可以重新创建你的场景吗?这是一种方式。我删除了索引和函数,然后让另一个使用teh table上的所有权限...

SQL> drop index promotions_fbi;

Index dropped.

SQL> drop function PROMO_FUNCTION;

Function dropped.

SQL> grant all on promotions to B;

Grant succeeded.

SQL> 

作为该用户,我可以创建一个正常的索引......

SQL> conn b/b
Connected.
SQL> select * from apc.promotions;

no rows selected

SQL> CREATE INDEX promotions_i
  2      ON APC.PROMOTIONS (promo_category);

Index created.

SQL> 

但是,如果我创建一个函数,我就无法使用它来创建基于函数的索引....

SQL> conn b/b
Connected.

SQL> CREATE INDEX promotions_fbi
  2        ON APC.PROMOTIONS (promo_function (promo_category));
      ON APC.PROMOTIONS (promo_function (promo_category))
                         *
ERROR at line 2:
ORA-00904: : invalid identifier

SQL>

无效标识符指向函数名称。为什么?因为虽然模式B将拥有索引模式,但APC拥有该表,并且还需要能够执行该函数。 解决方案是将函数的执行权限授予表所有者:

SQL> conn b/b
Connected.
SQL> grant execute on promo_function to APC;

Grant succeeded.

SQL> CREATE INDEX promotions_fbi
   2   ON APC.PROMOTIONS (B.promo_function (promo_category));  
Index created.

SQL> 

请注意,我们必须在此语句中显式引用函数所有者以及表所有者。这有点令人讨厌,这就是为什么以这种方式在两个模式中传播权限通常是个坏主意。


不确定@zaratustra如何获得他们的发现,因为我绝对可以在名称中使用单词FUNCTION创建基于函数的索引...

SQL> r
  1  select i.table_owner, i.owner as index_owner, i.index_name
  2         , i.index_type, e.column_expression
  3  from all_indexes i
  4       left join all_ind_expressions e
  5           on i.owner = e.index_owner
  6             and i.index_name = e.index_name
  7* where i.table_name = 'PROMOTIONS'

TABLE_OWNER                    INDEX_OWNER
------------------------------ ------------------------------
INDEX_NAME                     INDEX_TYPE
------------------------------ ---------------------------
COLUMN_EXPRESSION
--------------------------------------------------------------------------------
APC                            APC
PROMOTIONS_FBI                 FUNCTION-BASED NORMAL
"APC"."PROMO_FUNCTION"("PROMO_CATEGORY")

APC                            A
PROMO_B_I                      FUNCTION-BASED NORMAL
"A"."B_FUNCTION"("PROMO_CATEGORY")

APC                            APC
PROMOTIONS_I                   NORMAL



SQL> 

虽然我处于不同的点上,所以可以解释它

SQL> select banner from v$version;

BANNER
--------------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.2.0 - Production

SQL> 

答案 1 :(得分:0)

在我的实验中,我意识到Oracle不允许您使用过程名称中的函数字创建基于函数的索引。对我来说看起来像个错误:

CREATE OR REPLACE FUNCTION func_function(p_promo_category IN VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
  RETURN UPPER(p_promo_category);
END func_function;

create table t1 (
  promo_category varchar2(4000)
);

Table created

CREATE INDEX promotions_fbi ON t1 (func_function (promo_category));

ORA-00911: invalid character

让我们在名称中创建一个没有功能词的函数:

CREATE OR REPLACE FUNCTION func_functio(p_promo_category IN VARCHAR2)
RETURN VARCHAR2 DETERMINISTIC IS
BEGIN
  RETURN UPPER(p_promo_category);
END func_functio;

CREATE INDEX promotions_fbi ON t1 (func_functio (promo_category));

Index created

select index_name, index_type 
  from user_indexes 
 where lower(index_name) = 'promotions_fbi'

INDEX_NAME      INDEX_TYPE
-------------------------------------
PROMOTIONS_FBI  FUNCTION-BASED NORMAL

我的Oracle版本:

select banner from v$version

BANNER
----------------------------------------------------------------------------
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production