最好的方式来封装复杂的Oracle PL / SQL光标逻辑作为视图?

问题描述 投票:4回答:6

我写的PL / SQL代码进行非规范化的表成一个备受easer - 查询表格。该代码使用临时表做一些工作,从原始表合并一些列在一起。

该逻辑被写入为pipelined table function,以下从连结条图案。该表函数使用PRAGMA AUTONOMOUS_TRANSACTION声明以允许临时表操作,并且还接受一个光标输入参数来限制非正规化某些ID值。

然后我创建的视图来查询表函数,在所有可能的ID值传递作为光标(该功能的其他用途将是更限制性的)。

我的问题:这一切真的有必要吗?有我完全错过了完成同样的事情的一个更简单的方法?

每次我触摸PL / SQL我得到我打字太多的印象。

更新:我来补充我处理给大家,我谈论的非正规化的概念表的草图。该表存储员工作业的历史记录,每一个激活行,(可能)终止行。这是可能的雇员同时拥有多个就业机会,以及同样的工作,一遍又一遍的在不连续的日期范围。例如:

| EMP_ID | JOB_ID | STATUS | EFF_DATE    | other columns...
|      1 |     10 | A      | 10-JAN-2008 |
|      2 |     11 | A      | 13-JAN-2008 |
|      1 |     12 | A      | 20-JAN-2008 |
|      2 |     11 | T      | 01-FEB-2008 |
|      1 |     10 | T      | 02-FEB-2008 |
|      2 |     11 | A      | 20-FEB-2008 |

查询是要弄清楚谁是工作时什么工作是不平凡的。所以,我的非规范化函数填充临时表只用日期范围为每个作业,在思想上光标通过任何EMP_IDs。传递EMP_IDs 1和2会产生以下:

| EMP_ID | JOB_ID | START_DATE  | END_DATE    |
|      1 |     10 | 10-JAN-2008 | 02-FEB-2008 |
|      2 |     11 | 13-JAN-2008 | 01-FEB-2008 |
|      1 |     12 | 20-JAN-2008 |             |
|      2 |     11 | 20-FEB-2008 |             |

END_DATE允许NULLs对于不具有规定的终止日期的工作。)

你可以想像,这个非规范化的形式是非常非常容易查询,但创造它 - 只要我可以告诉 - 需要一个临时表来存储中间结果(例如,工作记录进行激活行已被发现,但没有终止......还)。使用流水线表函数来填充临时表,然后返回它的行是我已经找到了如何做到这一点的唯一途径。

sql oracle plsql
6个回答
4
投票

我认为,一个办法的办法,这是使用分析功能...

我设置测试情况下,使用:

create table employee_job (
    emp_id integer,
    job_id integer,
    status varchar2(1 char),
    eff_date date
    );  

insert into employee_job values (1,10,'A',to_date('10-JAN-2008','DD-MON-YYYY'));
insert into employee_job values (2,11,'A',to_date('13-JAN-2008','DD-MON-YYYY'));
insert into employee_job values (1,12,'A',to_date('20-JAN-2008','DD-MON-YYYY'));
insert into employee_job values (2,11,'T',to_date('01-FEB-2008','DD-MON-YYYY'));
insert into employee_job values (1,10,'T',to_date('02-FEB-2008','DD-MON-YYYY'));
insert into employee_job values (2,11,'A',to_date('20-FEB-2008','DD-MON-YYYY'));

commit;

我已经使用了铅的功能获得下一个日期,然后把它包都作为一个子查询只是为了得到“A”记录,并添加结束日期(如果有)。

select
    emp_id,
    job_id,
    eff_date start_date,
    decode(next_status,'T',next_eff_date,null) end_date
from
    (
    select
        emp_id,
        job_id,
        eff_date,
        status,
        lead(eff_date,1,null) over (partition by emp_id, job_id order by eff_date, status) next_eff_date,
        lead(status,1,null) over (partition by emp_id, job_id order by eff_date, status) next_status
    from
        employee_job
    )
where
    status = 'A'
order by
    start_date,
    emp_id,
    job_id

我敢肯定有一些使用情况下,我已经错过了,但你的想法。解析函数是你的朋友:)

EMP_ID   JOB_ID     START_DATE     END_DATE            
  1        10       10-JAN-2008    02-FEB-2008         
  2        11       13-JAN-2008    01-FEB-2008         
  2        11       20-FEB-2008                              
  1        12       20-JAN-2008                              

1
投票

而不是输入参数为光标,我将有一个表变量(不知道Oracle有这样的事情我是一个TSQL的家伙)或填充另一个临时表的ID值,并在视图中加入就可以了/功能或你需要的地方。

在我诚实的意见光标唯一的一次是当你有循环。而当你要循环我总是建议做应用程序的逻辑数据库的那个之外。


1
投票

这听起来像你在这里即放弃一些读一致性:将有可能为您的临时表中的内容是不同步的源数据,如果你有并发修改数据修改。

如果不知道的要求,也不是你想要的复杂性来实现。我会尝试

  1. 定义视图,包含SQL(可能复杂的)逻辑,否则我添加一些PL / SQL与混合物;
  2. 甲流水线表函数,但是使用一个SQL集合类型(而不是临时表)。一个简单的例子是在这里:http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4447489221109

2号会给你运动部件少,解决您的一致性问题。

马修·巴特勒


1
投票

这里真正的问题是“只写”表设计 - 我的意思是,它很容易将数据插入到它,但棘手的和低效的获取有用的信息出来呢!您的“临时”表的结构为“永久”表应该有摆在首位。

也许你可以这样做:

  • 与更好的结构创建一个永久表
  • 填充它的第一个表中的数据相匹配
  • 定义在原始表数据库触发器来保持新表同步从现在开始

然后,你可以在新表中选择要执行的报告。


0
投票

我不能同意你的意见,HollyStyles。我也曾经是一个TSQL的家伙,并找到了一些Oracle的特质的多一点令人费解了。不幸的是,临时表是不是很方便在Oracle中,在这种情况下,其他现有的SQL逻辑期待直接查询表,所以我给它这个观点来代替。这确实存在于这个系统的数据库之外的任何应用程序逻辑。

甲骨文开发者们似乎更急切地比我想象中使用游标。由于PL / SQL的束缚和学科性质,这是更加令人惊讶。


0
投票

最简单的解决方法是:

  1. 创建一个包含正是您所需要ID的global temporary tableCREATE GLOBAL TEMPORARY TABLE tab_ids (id INTEGER) ON COMMIT DELETE ROWS;
  2. 填入你需要的ID的临时表。
  3. 使用EXISTS操作在你的程序中来选择仅在标识表中的行: SELECT yt.col1, yt.col2 FROM your\_table yt WHERE EXISTS ( SELECT 'X' FROM tab_ids ti WHERE ti.id = yt.id )

您也可以通过以逗号分隔的ID的字符串作为函数参数,并将其解析到一个表。这是通过一个单一的SELECT进行。想了解更多 - 问我如何:-)但它必须是一个单独的问题。

© www.soinside.com 2019 - 2024. All rights reserved.