如何将该Oracle存储过程中的SQL转换为动态SQL?

时间:2019-06-04 07:13:21

标签: oracle plsql

这不是骗子,谢谢

我有一个存储过程,它引用了dba_tables,还有一些引用了,这意味着它们将必须成为变量而不是硬编码值。因此,我一直在努力将过程中的核心SQL及其变量更改为动态SQL。我提出了这个问题,以便为想要重复问题的任何人创建表的结构。最终结果将是服务器目录中的.csv文件(如果存在相关的数据库链接,该文件将具有一些值。)但是,下面的条目将生成一个文件,并且如果照原样复制,该过程将成功编译。我的版本中有一个数据库链接,该位可以用您的global_name替换,也可以将其删除,因为否则代码只会查看您本地的dba_tables。

我所需要做的就是使代码能够编译并成功运行,但要使用动态SQL,这样我便可以放入任何表变量中了……有人可以帮忙吗?

--drop any tables before creating the new ones:

drop table TABLE_TRACKER;
drop table LINK_AND_MAIL;
drop table MV_PRD_SEG_DATA;
drop table bob_table;

--CONNECT AS YOUR USER:

CREATE DIRECTORY ESTIMATES AS '<path_name>';

GRANT READ, WRITE ON DIRECTORY ESTIMATES TO <USER>;

create table TABLE_TRACKER
(
  TABLENAME         VARCHAR2(35),
  CREATED_AT        VARCHAR2(20),
  PDU_TAB_TRUNCATED VARCHAR2(1),
  TRUNCTIME         VARCHAR2(40)
)
/

insert into TABLE_TRACKER (TABLENAME, CREATED_AT, PDU_TAB_TRUNCATED, TRUNCTIME)
values ('IN_PROGRESS_20190530052803', '30/05/2019 17:34:09', 'Y', '31/05/2019 16:24:40');
commit;

CREATE TABLE "LINK_AND_MAIL" 
   (    "LINK_NAME" VARCHAR2(35), 
    "EMAIL_ADDRESS" VARCHAR2(30), 
    "MDATE" DATE
   )
/


insert into LINK_AND_MAIL (LINK_NAME, EMAIL_ADDRESS, MDATE)
values ('DATABASE', 'bob@bob.com', to_date('31-05-2019 16:25:31', 'dd-mm-yyyy hh24:mi:ss')); 
commit;

CREATE TABLE "BOB_TABLE" 
   (    "TARGETSCHEMA" VARCHAR2(200), 
    "PRODUCTIONSCHEMA" VARCHAR2(200), 
    "PRODUCTIONDATABASE" VARCHAR2(200), 
    "TABLE_NAME" VARCHAR2(200), 
    "DRIVER_TABLE" VARCHAR2(200), 
    "MANDATORY_JOIN" VARCHAR2(200), 
    "ADDITIONAL_JOINS" VARCHAR2(200), 
    "TABLE_COMPRESSED" VARCHAR2(200))
/

insert into BOB_TABLE (TARGETSCHEMA, PRODUCTIONSCHEMA, PRODUCTIONDATABASE, TABLE_NAME, DRIVER_TABLE, MANDATORY_JOIN, ADDITIONAL_JOINS, TABLE_COMPRESSED)
values ('SIT_BOB', 'APIBOB', 'DB1', 'PARMS', null, null, null, 'Y'); 
commit;

CREATE TABLE "MV_PRD_SEG_DATA" 
   (    "LINK" VARCHAR2(35), 
    "OWNER" VARCHAR2(30), 
    "SEGMENT_NAME" VARCHAR2(30),
        "FLAG" VARCHAR2(30),
        "SUM_BYTES" NUMBER)
/


insert into MV_PRD_SEG_DATA (LINK, OWNER, SEGMENT_NAME, FLAG, SUM_BYTES)
values ('DB1', 'BOB', 'GENRC_COLM', 'T', 5);
COMMIT;

/

--This is the start of the procedure, now you've created the tables 
--it should compile okay

create or replace procedure ESTIMATE_PROC_BOB is

--variables
l_dblink varchar2(100) := '<WHATEEVS>'; -- put your global_name here to mimic db_link
file_handle UTL_FILE.file_type;
v_ts_name varchar2(30);
v_link_name varchar2(10);
v_csv_name varchar2(100);
TOTAL_ROW_COUNT NUMBER;
TOT_OBJECT_SIZE_MB NUMBER;
FULL_TABLE_COUNT NUMBER;
EST_ONE_ROW_MB NUMBER;
C_TOTAL_ROW_COUNT NUMBER;
SPACE_REQUIRED NUMBER;
v_total_driver_only NUMBER := 0;
--

begin

SELECT tablename into v_csv_name
FROM table_tracker
WHERE
CREATED_AT = (select MAX(CREATED_AT) from table_tracker);

select link_name into v_link_name from link_and_mail where mdate = (select max(mdate) from link_and_mail);
select distinct targetschema into v_ts_name from BOB_TABLE;

file_handle := utl_file.fopen('ESTIMATES_CSV', v_csv_name||'_EST_PROC.csv', 'w', 32767);

--

UTL_FILE.PUT_LINE(file_handle, ' ');
UTL_FILE.PUT_LINE(file_handle, 'The below report shows total row counts in PROD ');
UTL_FILE.PUT_LINE(file_handle, 'for entries with just a driver table only tables in the PDU document');
UTL_FILE.PUT_LINE(file_handle, 'If you see no entries here, you have no valid joins in your file.');
UTL_FILE.PUT_LINE(file_handle, ' ');
utl_file.put_line(file_handle, 'OWNER,TABLE_NAME,TOT_OBJECT_SIZE_MB,TOTAL_ROW_COUNT,FULL_TABLE_COUNT,EST_ONE_ROW_MB,SPACE_REQUIRED');

--main loop, this is the bit I need to be DYN SQL, can you help?

for rws in (
SELECT /*+ monitor parallel (4)*/ a.owner,
                        a.table_name,
                        b.driver_table,
                        b.mandatory_join,
                        sum(c.sum_bytes) TOT_OBJECT_SIZE_MB,
                        trunc(TOT_OBJECT_SIZE_MB / FULL_TABLE_COUNT,7) EST_ONE_ROW_MB,
                        (EST_ONE_ROW_MB * TOTAL_ROW_COUNT) SPACE_REQUIRED
                 FROM dba_tables a, 
                 BOB_TABLE b, 
                 MV_PRD_SEG_DATA c
                 WHERE a.table_name IN ( SELECT table_name
                                       FROM BOB_TABLE
                                       WHERE driver_table IS NOT NULL
                                             AND   additional_joins IS NULL
                                     )
                 AND   a.owner IN ( SELECT DISTINCT productionschema FROM BOB_TABLE c  )
                 and a.table_name = b.table_name
                 and a.table_name = c.segment_name
                 group by a.owner,a.table_name,b.driver_table,b.mandatory_join
               ORDER BY table_name
    )

loop

execute immediate' select /*+monitor parallel (10)*/ count(*) from ' ||rws.owner||'.'||rws.table_name || '@' || l_dblink||' b '||','||
rws.driver_table || '@' || l_dblink||' a ' ||' where ' ||rws.mandatory_join --||' and '||rws.additional_joins
into TOTAL_ROW_COUNT;

execute immediate' select /*+monitor parallel (10)*/ count(*) from ' ||rws.owner||'.'||rws.table_name || '@' || l_dblink
into C_TOTAL_ROW_COUNT;

utl_file.put_line(file_handle,
                      rws.OWNER || ',' ||
                      rws.TABLE_NAME || ',' ||
                      rws.TOT_OBJECT_SIZE_MB || ',' ||
                      TOTAL_ROW_COUNT || ',' ||
                      C_TOTAL_ROW_COUNT || ',' || /* This is actually FULL_TABLE_COUNT*/
                      round(rws.TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7)|| ',' ||
                      round(round(rws.TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7) * round(TOTAL_ROW_COUNT,0),0)--SPACE_REQUIRED
                      );


v_total_driver_only := v_total_driver_only + round(rws.TOT_OBJECT_SIZE_MB / C_TOTAL_ROW_COUNT,7) * round(TOTAL_ROW_COUNT,0);

end loop;

UTL_FILE.PUT_LINE(file_handle, ' ');
utl_file.put_line(file_handle,
                     'Total Estimated Space Required '|| round(v_total_driver_only,0) ||' MB'
                     );
--

utl_file.fclose(file_handle);

end ESTIMATE_PROC_BOB;
/

1 个答案:

答案 0 :(得分:0)

与不使用动态SQL相比,使用动态SQL的游标循环的语法要复杂得多,但是一旦您看到了一些示例,它就应该变得如此工作。来自PL/SQL User's Guide and Reference - 10g Release 1 (10.1) - OPEN-FOR-USING Statement的简单示例:

DECLARE
   TYPE EmpCurTyp IS REF CURSOR;  -- define weak REF CURSOR type
   emp_cv   EmpCurTyp;  -- declare cursor variable
   my_ename VARCHAR2(15);
   my_sal   NUMBER := 1000;
BEGIN
   OPEN emp_cv FOR  -- open cursor variable
      'SELECT ename, sal FROM emp WHERE sal > :s' USING my_sal;
   ...
END;

这是另一个没有USING子句的示例:Open cursor with a dynamic select statement

Google将向您展示更多示例。搜索“ Oracle开放游标动态SQL”。再举一个例子:Dynamic SQL with ref cursor