Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/75.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/selenium/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 帽子_Sql_Oracle_Plsql - Fatal编程技术网

Sql 帽子

Sql 帽子,sql,oracle,plsql,Sql,Oracle,Plsql,乍一看,这段代码看起来像是在构建一个动态SQL语句来获取一些数据。所谓动态,我的意思是SQL语句是在运行时构建的,而过程是基于传入的参数构造where子句 最后,他们正在做: 打开e_sql的rrc_rectyp 这基本上将查询结果放在ref游标中,这允许客户端获取结果数据 顺便说一下,以这种方式使用动态SQL对性能非常不利,因为它会导致难以解析。您可以阅读更多关于硬解析以及为什么它们在链接中是邪恶的。解决方案是使用一个上下文,这样您就可以利用绑定变量的优点并避免硬解析(这将在该链接中讨论) 编

乍一看,这段代码看起来像是在构建一个动态SQL语句来获取一些数据。所谓动态,我的意思是SQL语句是在运行时构建的,而过程是基于传入的参数构造where子句

最后,他们正在做:

打开e_sql的rrc_rectyp

这基本上将查询结果放在ref游标中,这允许客户端获取结果数据

顺便说一下,以这种方式使用动态SQL对性能非常不利,因为它会导致难以解析。您可以阅读更多关于硬解析以及为什么它们在链接中是邪恶的。解决方案是使用一个上下文,这样您就可以利用绑定变量的优点并避免硬解析(这将在该链接中讨论)

编辑
实际上,他们正在将结果数据管道化到一个集合变量中。请参阅链接,并搜索“分配表函数的结果”。

它看起来像一个报告函数。它构建一个SQL语句,其中包含一些条件(WHERE中的一些元素依赖于参数)

查询本身看起来相当复杂。它使用带的
构造,允许您在查询中定义某种内联视图。这本身更多的是一个SQL(可能是Oracle SQL)特性,而不是PLSQL

然后,在游标中打开查询(在字符串变量中构建)。游标可以看作是遍历查询结果的工具,查询在这里以循环方式完成

然后,来自光标的变量被放入
v_行的属性中<代码>v_行
被声明为
记录类型
。它是一个可以重新表示记录的对象。对象通过管道传输到输出,这意味着此函数实际上返回一个记录集,这意味着您可以在查询中调用它,如下所示:

select * from table(monthly_analysis(<parameters>))

你确定你把所有的东西都贴出来了吗?因为现在,它永远不会成功运行。声明了很多变量,但从未使用过<例如,代码>e_sql
正在执行,但从未分配值

我希望您不要试图通过查看这些代码来学习PL/SQL,因为几乎每一行代码都会让我畏缩。特别是将变量声明为LONG(您不应该再使用它)、使用该记录以及笨拙的日期处理。哎哟,哎哟,哎哟!最重要的是,如果有人编写这样的代码,那么肯定需要学习如何评论他正在做的事情


更新

我重写了这个函数,现在它已经完成了。我用这些辅助对象测试了它:

SQL> create table ap_main
  2  ( cep_work_item_no number
  3  , received_date    date
  4  , req_accept_date  date
  5  , status_id        number
  6  , stage_id         number
  7  , country_id       number
  8  , sub_region_id    number
  9  , customer_type_id number
 10  , customer_id      number
 11  , priority_id      number
 12  , workgroup_id     number
 13  , city_id          number
 14  )
 15  /

Table created.

SQL> insert into ap_main
  2  select 1,sysdate,sysdate,1,4,1,1,1,1,1,1,1 from dual union all
  3  select 2,sysdate,sysdate,1,4,1,1,1,1,1,1,1 from dual union all
  4  select 3,sysdate,sysdate,1,5,1,1,1,1,1,1,1 from dual union all
  5  select 4,sysdate,sysdate,1,5,1,1,1,1,1,1,1 from dual union all
  6  select 5,sysdate,sysdate,2,5,1,1,1,1,1,1,1 from dual union all
  7  select 6,sysdate-31,sysdate-31,1,5,1,1,1,1,1,1,1 from dual union all
  8  select 7,sysdate-31,sysdate-31,1,5,1,1,1,1,1,1,1 from dual union all
  9  select 8,sysdate-31,sysdate-31,3,5,1,1,1,1,1,1,1 from dual
 10  /

8 rows created.

SQL> create table lk_customer (customer_id,customer_name)
  2  as
  3  select 1, 'Anna' from dual union all
  4  select 2, 'Bob' from dual
  5  /

Table created.

SQL> create type analysis_report_row_type as object
  2  ( months               varchar2(7)
  3  , orderby_months       varchar2(7)
  4  , req_received         number
  5  , req_still_open       number
  6  , req_await_acceptance number
  7  , req_with_att         number
  8  , req_closed           number
  9  , req_cancelled        number
 10  )
 11  /

Type created.

SQL> create type analysis_report_tab_type as table of analysis_report_row_type
  2  /

Type created.

SQL> create function convert_time
  2  ( p1 in date
  3  , p2 in varchar2
  4  , p3 in varchar2
  5  ) return date
  6  is
  7  begin
  8    return p1;
  9  end;
 10  /

Function created.

SQL> create package ecep_ap_utils
  2  as
  3    function f_business_days(p1 in date,p2 in date) return number;
  4  end ecep_ap_utils;
  5  /

Package created.

SQL> create package body ecep_ap_utils
  2  as
  3    function f_business_days(p1 in date,p2 in date) return number
  4    is
  5    begin
  6          return p2 - p1;
  7    end f_business_days;
  8  end ecep_ap_utils;
  9  /

Package body created.
函数的两个参数没有使用,所以我删除了它们。所有参数似乎都有错误的类型,所以我也修复了它。此外,我删除了所有不必要的变量,并使您的查询使用绑定变量。这一点很重要,因为Oracle将每个唯一的已解析语句存储在共享池中以供重用。但是,通过粘入参数,您使每个语句都是唯一的,从而导致难以解析并填满了共享池

您的函数是一个流水线函数,这在您的情况下似乎有些过分,因为您的结果集不会很大,因为您是按月份分组的。所以你每个月只能得到一排。我把它放在原处了。查询访问ap_主表六次,其中一次就足够了。您可能会注意到,通过性能提升。我仍然担心的是日期的处理。最初的程序员无法决定是使用字符串还是日期来处理日期。当然,您应该使用日期来处理日期。许多被调用的转换例程可能会以某种方式被跳过。无论如何。。。以下是新功能:

SQL> create function analysis
  2  ( country_id_p         in number
  3  , sub_region_id_p      in number
  4  , customer_type_id_p   in number
  5  , received_from_date_p in date
  6  , received_to_date_p   in date
  7  , customer_id_p        in number
  8  , priority_id_p        in number
  9  , work_group_id_p      in number
 10  , city_id_p            in number
 11  ) return analysis_report_tab_type pipelined
 12  is
 13    l_current_date        date;
 14    l_refcursor           sys_refcursor;
 15    l_analysis_report_row analysis_report_row_type := analysis_report_row_type(null,null,null,null,null,null,null,null);
 16  begin
 17    select sysdate + to_number(to_char(systimestamp, 'tzh')) / 24
 18      into l_current_date
 19      from dual
 20    ;
 21    open l_refcursor for
 22      'select analysis_report_row_type
 23              ( to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/yyyy'')
 24              , to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'')
 25              , count(cep_work_item_no)
 26              , count(case when received_date is not null and status_id=1 then 1 end)
 27              , count(case when req_accept_date is null and ecep_ap_utils.f_business_days(received_date,:p_current_date)>30 then 1 end)
 28              , count(case when req_accept_date is not null and status_id = 1 and stage_ID not in (4,10) and ecep_ap_utils.f_business_days(received_date,:p_current_date)>30 then 1 end)
 29              , count(case when status_id = 2 then 1 end)
 30              , count(case when status_id = 3 then 1 end)
 31              )
 32         from ap_main
 33        where received_date is not null ' ||
 34      case
 35      when country_id_p is null then
 36        ' and (1=1 or :p_country_id is null)'
 37      else
 38        ' and country_id = :p_country_id'
 39      end ||
 40      case
 41      when sub_region_id_p is null then
 42        ' and (1=1 or :p_sub_region_id is null)'
 43      else
 44        ' and sub_region_id = :p_sub_region_id'
 45      end ||
 46      case
 47      when customer_type_id_p is null then
 48        ' and (1=1 or :p_customer_type_id is null)'
 49      else
 50        ' and customer_type_id = :p_customer_type_id'
 51      end ||
 52      case
 53      when received_from_date_p is null then
 54        ' and (1=1 or :p_received_from_date is null)'
 55      else
 56        ' and convert_time(received_date, ''GMT'', ''GMT'') >= convert_time(trunc(:p_received_from_date), ''Europe/Paris'', ''GMT'')'
 57      end ||
 58      case
 59      when received_to_date_p is null then
 60        ' and (1=1 or :p_received_to_date is null)'
 61      else
 62        ' and convert_time(received_date, ''GMT'', ''GMT'') <= convert_time(trunc(:p_received_to_date), ''Europe/Paris'', ''GMT'')'
 63      end ||
 64      case
 65      when customer_id_p is null then
 66        ' and (1=1 or :p_customer_id is null)'
 67      else
 68        ' and customer_id in (select customer_id from lk_customer where upper(customer_name) like upper(:p_customer_id || ''%''))'
 69      end ||
 70      case
 71      when priority_id_p is null then
 72        ' and (1=1 or :p_priority_id is null)'
 73      else
 74        ' and priority_id = :p_priority_id'
 75      end ||
 76      case
 77      when work_group_id_p is null then
 78        ' and (1=1 or :p_workgroup_id is null)'
 79      else
 80        ' and workgroup_id = :p_workgroup_id'
 81      end ||
 82      case
 83      when city_id_p is null then
 84        ' and (1=1 or :p_city_id is null)'
 85      else
 86        ' and city_id = :p_city_id'
 87      end ||
 88      ' group by to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/yyyy'')
 89            , to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'')'
 90    using l_current_date
 91    ,     l_current_date
 92    ,     country_id_p
 93    ,     sub_region_id_p
 94    ,     customer_type_id_p
 95    ,     received_from_date_p
 96    ,     received_to_date_p
 97    ,     customer_id_p
 98    ,     priority_id_p
 99    ,     work_group_id_p
100    ,     city_id_p
101    ;
102    loop
103      fetch l_refcursor into l_analysis_report_row;
104      exit when l_refcursor%notfound;
105      pipe row (l_analysis_report_row);
106    end loop;
107    return;
108  end analysis;
109  /

Function created.

更新2

以下是指向此处使用的两个关键结构的两个链接:

公开发表声明:

流水线功能:

正如您在OpenFor语句文档中所看到的,在FOR之后,您可以指定一个查询,我将动态构造该查询。在您的原始代码中也进行了同样的操作。不同之处在于,我使用的是本机动态SQL,因此我可以使用绑定变量(以“:p_”开头的变量)。我这样做的方式是,无论我提供什么输入值,所有绑定变量都存在于查询中。以下是一个很好的解释,说明了原因和方式:

如果你还有其他问题,尽管问吧

问候,,
Rob.

请发表评论,解释结束问题的原因,我准备添加更多内容或根据建议进行修改,如果这不是该问题的正确位置,请告诉我,我将相应地移动它。亲密选民,“太本地化”不是“tl;dr”的同义词,尽管以“太”开头。+1到BoltClock。PL/SQL不再被认为是StackOverflow的一个合法主题了吗?目前,三个投票中有两个赞成过于本地化,另一个不是真正的问题。我猜那些人觉得解释一段现有的代码不是SO的主要指令的一部分,因为这不太可能引起更广泛的兴趣。我本人在看到两张结束问题的投票后投票赞成结束这个问题,因为我认为要求SO读者解释其他人的代码是正确的,但我真的很难理解它,所以将其张贴在这里,以便我可以获得一些专家建议。什么does
v_row AP_ANALYSIS_REPORT_row_TYPE:=AP_ANALYSIS_REPORT_row_TYPE(null,null,…)行do,它的目的是什么?那只是创建记录。因为它是一个管道函数,所以不需要创建一个集合来保存记录,但需要一条记录来保存希望为每行管道传递的值。@GolezTrol:Yes,它用于报告目的,其结果集取决于输入参数。根据您的经验,这是编写报告函数的通用方法还是有一些最佳做法?我通常会尝试阻止以这种方式构建SQL。我宁愿通过参数
SQL> create table ap_main
  2  ( cep_work_item_no number
  3  , received_date    date
  4  , req_accept_date  date
  5  , status_id        number
  6  , stage_id         number
  7  , country_id       number
  8  , sub_region_id    number
  9  , customer_type_id number
 10  , customer_id      number
 11  , priority_id      number
 12  , workgroup_id     number
 13  , city_id          number
 14  )
 15  /

Table created.

SQL> insert into ap_main
  2  select 1,sysdate,sysdate,1,4,1,1,1,1,1,1,1 from dual union all
  3  select 2,sysdate,sysdate,1,4,1,1,1,1,1,1,1 from dual union all
  4  select 3,sysdate,sysdate,1,5,1,1,1,1,1,1,1 from dual union all
  5  select 4,sysdate,sysdate,1,5,1,1,1,1,1,1,1 from dual union all
  6  select 5,sysdate,sysdate,2,5,1,1,1,1,1,1,1 from dual union all
  7  select 6,sysdate-31,sysdate-31,1,5,1,1,1,1,1,1,1 from dual union all
  8  select 7,sysdate-31,sysdate-31,1,5,1,1,1,1,1,1,1 from dual union all
  9  select 8,sysdate-31,sysdate-31,3,5,1,1,1,1,1,1,1 from dual
 10  /

8 rows created.

SQL> create table lk_customer (customer_id,customer_name)
  2  as
  3  select 1, 'Anna' from dual union all
  4  select 2, 'Bob' from dual
  5  /

Table created.

SQL> create type analysis_report_row_type as object
  2  ( months               varchar2(7)
  3  , orderby_months       varchar2(7)
  4  , req_received         number
  5  , req_still_open       number
  6  , req_await_acceptance number
  7  , req_with_att         number
  8  , req_closed           number
  9  , req_cancelled        number
 10  )
 11  /

Type created.

SQL> create type analysis_report_tab_type as table of analysis_report_row_type
  2  /

Type created.

SQL> create function convert_time
  2  ( p1 in date
  3  , p2 in varchar2
  4  , p3 in varchar2
  5  ) return date
  6  is
  7  begin
  8    return p1;
  9  end;
 10  /

Function created.

SQL> create package ecep_ap_utils
  2  as
  3    function f_business_days(p1 in date,p2 in date) return number;
  4  end ecep_ap_utils;
  5  /

Package created.

SQL> create package body ecep_ap_utils
  2  as
  3    function f_business_days(p1 in date,p2 in date) return number
  4    is
  5    begin
  6          return p2 - p1;
  7    end f_business_days;
  8  end ecep_ap_utils;
  9  /

Package body created.
SQL> create function analysis
  2  ( country_id_p         in number
  3  , sub_region_id_p      in number
  4  , customer_type_id_p   in number
  5  , received_from_date_p in date
  6  , received_to_date_p   in date
  7  , customer_id_p        in number
  8  , priority_id_p        in number
  9  , work_group_id_p      in number
 10  , city_id_p            in number
 11  ) return analysis_report_tab_type pipelined
 12  is
 13    l_current_date        date;
 14    l_refcursor           sys_refcursor;
 15    l_analysis_report_row analysis_report_row_type := analysis_report_row_type(null,null,null,null,null,null,null,null);
 16  begin
 17    select sysdate + to_number(to_char(systimestamp, 'tzh')) / 24
 18      into l_current_date
 19      from dual
 20    ;
 21    open l_refcursor for
 22      'select analysis_report_row_type
 23              ( to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/yyyy'')
 24              , to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'')
 25              , count(cep_work_item_no)
 26              , count(case when received_date is not null and status_id=1 then 1 end)
 27              , count(case when req_accept_date is null and ecep_ap_utils.f_business_days(received_date,:p_current_date)>30 then 1 end)
 28              , count(case when req_accept_date is not null and status_id = 1 and stage_ID not in (4,10) and ecep_ap_utils.f_business_days(received_date,:p_current_date)>30 then 1 end)
 29              , count(case when status_id = 2 then 1 end)
 30              , count(case when status_id = 3 then 1 end)
 31              )
 32         from ap_main
 33        where received_date is not null ' ||
 34      case
 35      when country_id_p is null then
 36        ' and (1=1 or :p_country_id is null)'
 37      else
 38        ' and country_id = :p_country_id'
 39      end ||
 40      case
 41      when sub_region_id_p is null then
 42        ' and (1=1 or :p_sub_region_id is null)'
 43      else
 44        ' and sub_region_id = :p_sub_region_id'
 45      end ||
 46      case
 47      when customer_type_id_p is null then
 48        ' and (1=1 or :p_customer_type_id is null)'
 49      else
 50        ' and customer_type_id = :p_customer_type_id'
 51      end ||
 52      case
 53      when received_from_date_p is null then
 54        ' and (1=1 or :p_received_from_date is null)'
 55      else
 56        ' and convert_time(received_date, ''GMT'', ''GMT'') >= convert_time(trunc(:p_received_from_date), ''Europe/Paris'', ''GMT'')'
 57      end ||
 58      case
 59      when received_to_date_p is null then
 60        ' and (1=1 or :p_received_to_date is null)'
 61      else
 62        ' and convert_time(received_date, ''GMT'', ''GMT'') <= convert_time(trunc(:p_received_to_date), ''Europe/Paris'', ''GMT'')'
 63      end ||
 64      case
 65      when customer_id_p is null then
 66        ' and (1=1 or :p_customer_id is null)'
 67      else
 68        ' and customer_id in (select customer_id from lk_customer where upper(customer_name) like upper(:p_customer_id || ''%''))'
 69      end ||
 70      case
 71      when priority_id_p is null then
 72        ' and (1=1 or :p_priority_id is null)'
 73      else
 74        ' and priority_id = :p_priority_id'
 75      end ||
 76      case
 77      when work_group_id_p is null then
 78        ' and (1=1 or :p_workgroup_id is null)'
 79      else
 80        ' and workgroup_id = :p_workgroup_id'
 81      end ||
 82      case
 83      when city_id_p is null then
 84        ' and (1=1 or :p_city_id is null)'
 85      else
 86        ' and city_id = :p_city_id'
 87      end ||
 88      ' group by to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''mm/yyyy'')
 89            , to_char(convert_time(received_date, ''GMT'', ''Europe/Paris''),''yyyy/mm'')'
 90    using l_current_date
 91    ,     l_current_date
 92    ,     country_id_p
 93    ,     sub_region_id_p
 94    ,     customer_type_id_p
 95    ,     received_from_date_p
 96    ,     received_to_date_p
 97    ,     customer_id_p
 98    ,     priority_id_p
 99    ,     work_group_id_p
100    ,     city_id_p
101    ;
102    loop
103      fetch l_refcursor into l_analysis_report_row;
104      exit when l_refcursor%notfound;
105      pipe row (l_analysis_report_row);
106    end loop;
107    return;
108  end analysis;
109  /

Function created.
SQL> select * from table(analysis(1,1,1,null,null,1,1,1,1))
  2  /

no rows selected

SQL> select * from table(analysis(null,null,null,null,null,null,null,null,null))
  2  /

MONTHS  ORDERBY REQ_RECEIVED REQ_STILL_OPEN REQ_AWAIT_ACCEPTANCE REQ_WITH_ATT REQ_CLOSED REQ_CANCELLED
------- ------- ------------ -------------- -------------------- ------------ ---------- -------------
12/2010 2010/12            5              4                    0            0          1             0
11/2010 2010/11            3              2                    0            2          0             1

2 rows selected.