我写的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_ID
s。传递EMP_ID
s 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
允许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值,并在视图中加入就可以了/功能或你需要的地方。
在我诚实的意见光标唯一的一次是当你有循环。而当你要循环我总是建议做应用程序的逻辑数据库的那个之外。
这听起来像你在这里即放弃一些读一致性:将有可能为您的临时表中的内容是不同步的源数据,如果你有并发修改数据修改。
如果不知道的要求,也不是你想要的复杂性来实现。我会尝试
2号会给你运动部件少,解决您的一致性问题。
马修·巴特勒
这里真正的问题是“只写”表设计 - 我的意思是,它很容易将数据插入到它,但棘手的和低效的获取有用的信息出来呢!您的“临时”表的结构为“永久”表应该有摆在首位。
也许你可以这样做:
然后,你可以在新表中选择要执行的报告。
我不能同意你的意见,HollyStyles。我也曾经是一个TSQL的家伙,并找到了一些Oracle的特质的多一点令人费解了。不幸的是,临时表是不是很方便在Oracle中,在这种情况下,其他现有的SQL逻辑期待直接查询表,所以我给它这个观点来代替。这确实存在于这个系统的数据库之外的任何应用程序逻辑。
甲骨文开发者们似乎更急切地比我想象中使用游标。由于PL / SQL的束缚和学科性质,这是更加令人惊讶。
最简单的解决方法是:
CREATE GLOBAL TEMPORARY TABLE tab_ids (id INTEGER)
ON COMMIT DELETE ROWS;
SELECT yt.col1, yt.col2 FROM your\_table yt
WHERE EXISTS (
SELECT 'X' FROM tab_ids ti
WHERE ti.id = yt.id
)
您也可以通过以逗号分隔的ID的字符串作为函数参数,并将其解析到一个表。这是通过一个单一的SELECT进行。想了解更多 - 问我如何:-)但它必须是一个单独的问题。