【问题标题】:Efficiency of quarterly calculation of workforce headcount季度计算劳动力人数的效率
【发布时间】:2013-08-28 17:05:15
【问题描述】:

我有一张表 per_all_peopl_f,其中包含以下列:

name  person_id  emp_flag  effective_start_date   effective_end_date   DOJ
--------------------------------------------------------------------------------    
ABC   123          Y       30-MAR-2011              30-MAR-2013       10-FEB-2011
ABC   123          Y       24-FEB-2011              27-FEB-2011       10-FEB-2011
DEF   345          N       10-APR-2012              30-DEC-4712       15-SEP-2011

有许多条目 (1000+) 具有重复的数据和不同的生效开始日期。

我必须计算员工人数。即每季度退出公司的员工人数。

必须提取以下列:

  1. 2012 年员工人数(第一季度)
  2. 2013 年员工人数(第一季度)
  3. 两个员工人数的差异
  4. % 差异

我用来按季度查找人数的查询是:

函数1:

CREATE OR REPLACE FUNCTION function_name
  (l_end_date ,l_start_date  ) 
  RETURN number;
  IS 
    l_emp

  BEGIN
    select count(distinct papf.person_id)
      into l_emp
      from per_all_people_f papf
     where papf.emp_flag ='Y'
       and effective_start_date >=l_end_date
       and effective_end_date <=l_start_date ;

    return l_emp; 
END function_name;

主包:

create xx_pack_name  body
is 
    cursor cur_var
    is 
       select function_name('01-MAR-2012','31-MAY-2012') EMP_2012,
              function_name('01-MAR-2013','31-MAY-2013') EMP_2013,
              function_name('01-MAR-2012','31-MAY-2012')-function_name('01-MAR-2013','31-MAY-2013') Diff
         from dual;

end xx_pack_name  ;

这是否具有成本效益?

【问题讨论】:

  • 我不确定我是否理解这个问题——“成本效益”是非常主观的。您是在问“有没有办法提高效率?”如果是这样,您使用的是哪个版本的 Oracle?什么版本?是否配置了结果缓存?是否有某些原因需要定义一个游标来返回单行的结果?您是否有理由要在包裹中硬编码日期?
  • 不,我不会硬编码日期……它只是一个草稿代码……
  • 高效是指更好的代码
  • 您如何定义 Qtr 的人数? Qtr 开始时的计数、结束时的计数、本季度任何一天在公司中的员工计数,还是别的什么?
  • 我很困惑,你这样称呼你的函数 `function_name(l_end_date=>'01-MAR-2012', l_start_date=>'31-MAY-2012')。开始日期大于结束日期,您能检查一下您的代码吗?

标签: sql oracle plsql


【解决方案1】:

如果在per_all_people_f 表的至少effective_start_dateeffective_end_date 字段上有索引,这似乎是一个很好的变体。

这个查询的理想变体是

create index x_per_all_people_search on per_all_people_f(   
  effective_start_date,
  effective_end_date, 
  person_id,  
  emp_flag
)

但维护起来可能过于昂贵(磁盘成本、插入速度)。

另外,包体中的游标必须包含子查询和复用函数调用结果:

cursor cur_var
is 
  select 
    EMP_2012,
    EMP_2013,
    (EMP_2013 - EMP_2012) Diff
  from (
   select 
     function_name('01-MAR-2012','31-MAY-2012') EMP_2012,
     function_name('01-MAR-2013','31-MAY-2013') EMP_2013
   from dual
  );

当然最好的解决方案是最小化上下文切换并从单个 SQL 查询中获取所有值。此外,您可以直接向光标提供参数:

cursor cur_var(
  start_1 date, end_1 date, 
  start_2 date, end_2 date
)
is 
  select 
    EMP_2012,
    EMP_2013,
    (EMP_2013 - EMP_2012) Diff
  from (
   select 
     (
       select 
         count(distinct papf.person_id)
       from 
         per_all_people_f papf
       where 
         papf.emp_flag = 'Y'
         and 
         effective_start_date >= trunc(start_1)
         and 
         effective_end_date   <= trunc(end_1)
     ) EMP_2012,
     (
       select 
         count(distinct papf.person_id)
       from 
         per_all_people_f papf
       where 
         papf.emp_flag = 'Y'
         and 
         effective_start_date >= trunc(start_2)
         and 
         effective_end_date   <= trunc(end_2)
     ) EMP_2013
   from dual
  );

从我的角度来看,函数/光标参数太通用了,最好创建一个将季度数和两年作为输入参数的包装器进行比较。

最后,如果计划在 PL/SQL 中使用结果(我想是因为返回单行)根本不使用游标,只需通过输出参数返回计算值。从另一个角度来看,如果您需要在一个游标中获取全年的季度数据,那么计算所有季度并在单个查询中进行比较可能会更有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多