最好的方式来封装复杂Oracle PL/SQL标的逻辑作为一个观点?
题
我已经写PL/SQL代码非规范化表进入一个非常更容易到查询的形式。代码使用一个临时的表做一些工作,合并某些行从原来的表一起。
其中的逻辑是写作 流水线表的功能, 下图从本链接文章。表格功能的使用 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_ID
s传虽然光标。通过在 EMP_ID
s1和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
允许 NULL
s工作,没有预定的终止日期。)
你可以想象,这种非标准化的形成是多少,更容易查询,但是创造它--到目前为止,我可以告诉--需要一个临时表以储存的中间结果(例如,工作的记录其活行已发现,但不是终止...)。利用流水线表的功能来填充的临时表格,然后返回其行是唯一的办法,我已经想通了,如何做到这一点。
解决方案
我想一个办法是使用的分析功能...
我设置了你的测试的情况下使用:
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
其他提示
而不是具有的输入参数的以光标,我有一个表变量(不知道如果Oracle有这样的事情我一TSQL人)或填充的另一个临时表与ID值和加入它在图/多功能或任何你需要的。
唯一的时间用于光标在我的诚实的意见是当你 已 循环。当你必须循环,我总是推荐做到这一外部的数据库应用程序的逻辑。
这听起来就像你是放弃一读的一致性在这里,即:这将有可能为内容的临时表格是不同步的源数据,如果有并发修改数据的修改。
不知道的要求,也不复杂,你想要什么来实现。我会尝试
- 定义来看,含有(可能是复杂的)的逻辑SQL,不然我会加入一些PL/SQL的混合;
- 一个流水线表功能,但用SQL收集型(而不是临时的表格)。一个简单例子是: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:4447489221109
2号会给你少移动部件和解决一致性问题。
马修*巴特勒
这里真正的问题是"只写"设计-我的意思是,这是易于插入数据,但棘手和效率低下,获得有用的信息。你的"临时"的表具有结构的"永久性"表应该有的放在第一位。
可能你也许是这样做:
- 建立一个永久性的表与更好的结构
- 填充到匹配的数据在第一桌
- 定义数据库的触发原始表保持新表同步从现在起
然后你就可以从中选择的新的表执行您的报告。
我不能同意与你更多的,HollyStyles.我也曾经是一个TSQL家伙,并找到一些Oracle的特性多一点令人费解。不幸的是,临时表不是作为方便在Oracle,并且在这种情况下,其他现有的SQL逻辑的期望,直接查询表,所以我给这个图代替。真的没有应用程序的逻辑存在数据库之外,在这个系统。
Oracle开发者似乎使用光标更加急切地比我们的想法。鉴于奴役和纪律的性质PL/SQL,这是更加令人吃惊。
最简单的解决方案是:
创建一个 全球的临时表格 只包含Id你需要:
CREATE GLOBAL TEMPORARY TABLE tab_ids (id INTEGER) ON COMMIT DELETE ROWS;
填充的临时表与标识的需要。
使用否存在操作过程可以选择的行只有在IDs表:
SELECT yt.col1, yt.col2 FROM your\_table yt WHERE EXISTS ( SELECT 'X' FROM tab_ids ti WHERE ti.id = yt.id )
你也可以通过一个逗号分隔串的标识作为一个功能的参数,并分析它变成一个表中。这是通过一个单一的选择。想知道更多-问我如何:-),但这必须是一个单独的问题。