【问题标题】:Why type of a view column does not match corresponding function result type?为什么视图列的类型与对应的函数结果类型不匹配?
【发布时间】:2020-02-13 22:50:08
【问题描述】:

假设有一个函数my_pkg.get_prop_of,它返回CHAR(5) 类型的值。 另外,让我们声明一个视图my_view,其中有一列prop,从这个函数调用中获得它的值。

create or replace package my_pkg AS

  subtype short_string is CHAR(5);

  function get_prop_of(pi_name char)
    return short_string;    
end;    

create or replace package body my_pkg AS

  function get_prop_of(pi_name char)
    return short_string is
  begin
    return substr(pi_name || 'abcde', 1, 5);
  end;    
end;
---

create or replace view my_view as
select 
       my_pkg.get_prop_of('x') as prop
  from dual;

您能否解释一下为什么数据字典将该列类型显示为VARCHAR2(4000),这种行为的目的是什么?

select table_name, data_Type, data_length
  from all_tab_cols
 where table_name = 'MY_VIEW';

----------------------------------------------------
 TABLE_NAME | COLUMN_NAME | DATA_TYPE | DATA_LENGTH
----------------------------------------------------
   MY_VIEW  |  PROP       |  VARCHAR2 |    4000

看起来数据字典包含让编译器在视图编译时应用它所需的数据。但不知何故,它没有那样做。

select object_name, package_name, data_type, data_length, in_out
  from all_arguments
 where object_name = 'GET_PROP_OF';

-----------------------------------------------------------------
  OBJECT_NAME  | PACKAGE_NAME | DATA_TYPE | DATA_LENGTH | IN_OUT
-----------------------------------------------------------------
  GET_PROP_OF  |    MY_PKG    |   CHAR    |      5      |  OUT     <- return type
  GET_PROP_OF  |    MY_PKG    |   CHAR    |             |  IN

我想以明确的方式获得列类型和函数结果类型的匹配。

众所周知,像CAST(val AS CHAR(5)) 这样的硬铸造可以暂时解决问题, 但是有没有更优雅的方法,它也可以处理更改函数返回类型的情况,而无需更改列中各处的CAST 表达式,调用该函数。

【问题讨论】:

    标签: oracle plsql view type-conversion column-types


    【解决方案1】:

    因为在创建VIEW 时,Oracle 不知道从function 返回的function 结果的最大值,但它知道数据类型。

    另外,事实是 --> 任何来自function 的返回值都不能包含data precision

    您仍然可以通过使用CAST 控制VIEW 查询中的数据类型和精度来达到您想要的效果,如下所示:

    SQL>
    SQL> CREATE OR REPLACE VIEW MY_VIEW AS
      2      SELECT
      3          CAST(MY_PKG.GET_PROP_OF('x') AS VARCHAR2(5)) AS PROP
      4      FROM
      5          DUAL;
    
    View created.
    
    SQL> DESC MY_VIEW;
     Name                                      Null?    Type
     ----------------------------------------- -------- ----------------------------
     PROP                                               VARCHAR2(5)
    
    SQL>
    

    干杯!!

    【讨论】:

    • 感谢您的回复。实际上,问题是当明确指定时,为什么 Oracle 不知道结果的确切类型。正如文中所述 - CAST 不能解决问题,只能隐藏它。更糟糕的是 - 它创建了类型声明的重复,并且将扩展 MY_PKG.short_string 的开发人员很容易错过视图中的大多数 ist 用法 - 并且编译器无法帮助他。
    • 因为在 oracle 中不允许精确返回结果。不能回NUMBER(2),只能回NUMBERVARCHAR2 和其他数据类型也是如此。
    • @diziaq 那么你的问题是关于为什么 PL/SQL 语言只考虑参数的基本类型而忽略精度/比例/长度的问题。
    • @WilliamRobertson,在我看来,在 PL/SQL 中,关于精度的一切都是正确的。尝试 SELECT DATA_TYPE,DATA_LENGTH FROM ALL_ARGUMENTS WHERE object_name = 'function_name',此外,在运行时,如果返回的字符串长度溢出,可能会引发类型不匹配异常。我试图理解的问题与所述完全一样:为什么视图列的类型与相应函数的返回类型不匹配,即使它是在编译时可导出的。
    【解决方案2】:

    因为您使用函数创建视图

    Function defining views data type as VARCHAR2(4000) affecting performance?

    create or replace view my_view as
    select 
           substr(my_pkg.get_prop_of('x'),0,5) q
      from dual;
    
      select table_name, data_Type, data_length
      from dba_tab_cols
     where table_name = 'MY_VIEW';
    
    
    
    MY_VIEW VARCHAR2    5
    

    【讨论】:

    • 有趣的是,为什么 Oracle 对 substr(x,0,5) 进行了特殊处理,并且可以识别确切的返回类型,但不能对非标准函数做同样的事情。
    • 我认为,因为 Oracle 默认不知道您的功能。 Substr 是他的字典(文档)中的函数
    • 尽管如此,SUBSTR 的返回类型只是 VARCHAR2,并且 Oracle 设法动态识别有一个 5 作为参数传递。在我看来,获得已知类型的编译函数比计算预期结果长度 substr(x, a, b) 执行 b-a+1 简单得多。
    • 为什么?只得到b
    • 我认为是最节俭的估计。我不知道为什么,但即使在您的示例中,如果我们将mlt 更改为dual,那么在dba_tab_cols 中我会看到VARCHAR2(20)。无论a 的值如何,substr(x,a,b) 的类型长度看起来都是4b。你知道为什么会这样吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-26
    • 1970-01-01
    相关资源
    最近更新 更多