2016-01-22 120 views
2

我的任务是改进旧的PL/SQL和Oracle SQL遗留代码。总共有大约7000行代码!现有代码的一个方面让我非常惊讶,以前的编码器通过不编写任何过程或函数而不必要地创建了数百行代码 - 相反,编码器实质上始终重复相同的代码。PL/SQL存储过程创建表

例如,在现有的代码字面上有以下SQL的40或更多次的重复:

CREATE TABLE tmp_clients 
AS 
    SELECT * FROM live.clients; 

CREATE TABLE tmp_customers 
AS 
    SELECT * FROM live.customers; 

CREATE TABLE tmp_suppliers 
AS 
    SELECT * FROM live.suppliers WHERE type_id = 1; 

and many, many more..... 

我很新在PL/SQL写,但我最近购买的优秀图书Steven Feuerstein的“Oracle PL/SQL编程”。然而,据我所知,我应该能够编写一个可调用的程序,例如:

procedure create_temp_table (new_table_nme in varchar(60) 
    source_table in varchar(60)) 
IS 
    s_query varchar2(100); 
BEGIN 
    s_query := 'CREATE TABLE ' + new_table_nme + 'AS SELECT * FROM ' + source_table; 
    execute immediate s_query; 

EXCEPTION 
    WHEN OTHERS THEN 
     IF SQLCODE = -955 THEN 
      NULL; 
     ELSE 
      RAISE; 
     END IF; 
END; 

然后,我会简单地调用过程如下:

create_temp_table('tmp.clients', 'live.clients'); 
create_temp_table('tmp.customers', 'live.customers'); 
  1. 是我的建议鉴于上述问题,合理的方法?
  2. 过程调用中的数据类型是否合理,即应该使用varchar2(60),还是可以强制'source_table'参数成为模式中的表名称?如果表名超过60个字符会发生什么?
  3. 我希望能够通过第三个非必需参数的情况下,数据必须在一个微不足道的限制,即处理案件“WHERE type_id = 1”。如何修改过程以包含仅偶尔使用的参数以及如何修改其余代码。我可能会添加某种IF/ELSE语句来检查第三个参数是否不为NULL,然后相应地构造s_query。
  4. 如何检查表格是否已成功创建?
  5. 我想陷阱其他两个例外,即

    • 新表(如“tmp.clients”)已经存在;和
    • 源表不存在。

    作为书面处理的EXCEPTION是否处理这些情况?

  6. 更一般地说,从哪里可以获得SQL错误代码及其含义?

任何建议对代码的改进都会非常感激地收到。

+2

只是使用全局临时表。创建表的代码让我认为原始人熟悉SQL Server。 – kevinsky

回答

2

通过使用GLOBAL临时表,您可以摆脱很多代码(逐渐!)。 立即执行并不是一个坏习惯,但如果有其他选项,那么应该使用它们。全局临时表在您想要提取和转换数据的地方很常见,但一旦经过处理,您不再需要它,直到下一次加载。每个用户只能看到他们插入的数据,并且不会生成重做日志。如果需要,您可以index the data更快地查询。

像这样的事情

- 创建表

create global temporary table GT_CLIENTS 
(
    id     NUMBER(10) not null, 
    Client_id    NUMBER(10) not null, 
    modified_by_id  NUMBER(10), 
    transaction_id  NUMBER(10), 
    local_transaction_id VARCHAR2(30) not null, 
    last_modified_date_tz TIMESTAMP(6) WITH TIME ZONE not null 
) 
on commit preserve rows; 

我建议在提交保存行选项,以便您可以调试你的程序,看什么地方到表中。

用法是

INSERT INTO GT_CLIENTS 
SELECT * FROM live.clients; 
+0

我不确定我关注。我明白全局临时表可以用来存储复杂查询的结果。然而,如果我所做的只是将现有生产环境中的现有表格复制到我自己的模式中,我看不出所提议的好处。 – user2948208

+0

除非我缺少重点,否则您的解决方案需要为每个全局临时表编写大量代码,即需要为GT_CLIENTS,GT_CUSTOMERS,GT_SUPPLIERS等编写单独的代码。这是我尝试的避免。 – user2948208

+0

我接受全球临时表还有其他好处(可能会降低内存或存储空间),我很乐意被别人说服,但目前我无法看到您提出的解决方案如何对我有利,纯粹是因为到需要编写的代码量。 – user2948208

0

如果这是你想采取尽量减少路由改变时,那么误差源表中不存在为-942,你会想停下来,而不是继续作为你的临时表不会被创建。同样,如果你得到的对象已经存在,只要继续,错误将会有问题,因为你不会用新数据重新加载它 - 创建失败,所以表仍然有来自上次运行的数据。所以我肯定会更多地考虑一下你的异常处理程序。

这就是说,我也认为这通常不是最好的办法。在多用户环境中创建和删除对象是一个灾难,当有更多合适的选项可用时,这似乎是一种愚蠢的资源浪费。

+0

感谢您建议代码-942。正如我上面评论的那样,我很乐意以“最好的方式”做事,但是你没有真正解释过,除了说你同意前面的人。为了达到这个目的,我可能会忽略全局临时表的要点,因为它似乎需要为每个这样的表编写大量的代码。此外,这并不是一个真正的多用户环境,尽管确实只需要很短的时间就可以将这些表作为较大查询的输入 – user2948208

+1

是的,您需要创建全局临时表,但是一旦创建完成像当前创建语句一样插入它们。因此,一旦它们处于模式中,就没有重要的额外编码,并且可以消除创建/删除对象的开销,并且GTT不会生成重做日志或回滚信息,从而显着减少向其中插入数据的开销。 –