我已经写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_IDs传虽然光标。通过在 EMP_IDs1和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工作,没有预定的终止日期。)

你可以想象,这种非标准化的形成是多少,更容易查询,但是创造它--到目前为止,我可以告诉--需要一个临时表以储存的中间结果(例如,工作的记录其活行已发现,但不是终止...)。利用流水线表的功能来填充的临时表格,然后返回其行是唯一的办法,我已经想通了,如何做到这一点。

有帮助吗?

解决方案

我想一个办法是使用的分析功能...

我设置了你的测试的情况下使用:

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值和加入它在图/多功能或任何你需要的。

唯一的时间用于光标在我的诚实的意见是当你 循环。当你必须循环,我总是推荐做到这一外部的数据库应用程序的逻辑。

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

不知道的要求,也不复杂,你想要什么来实现。我会尝试

  1. 定义来看,含有(可能是复杂的)的逻辑SQL,不然我会加入一些PL/SQL的混合;
  2. 一个流水线表功能,但用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,这是更加令人吃惊。

最简单的解决方案是:

  1. 创建一个 全球的临时表格 只包含Id你需要:

    CREATE GLOBAL TEMPORARY TABLE tab_ids (id INTEGER)  
    ON COMMIT DELETE ROWS;
    
  2. 填充的临时表与标识的需要。

  3. 使用否存在操作过程可以选择的行只有在IDs表:

      SELECT yt.col1, yt.col2 FROM your\_table yt  
       WHERE EXISTS (  
          SELECT 'X' FROM tab_ids ti  
           WHERE ti.id = yt.id  
       )
    

你也可以通过一个逗号分隔串的标识作为一个功能的参数,并分析它变成一个表中。这是通过一个单一的选择。想知道更多-问我如何:-),但这必须是一个单独的问题。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top