Как я могу преобразовать SQL в этой хранимой процедуре Oracle в динамический SQL? - PullRequest
0 голосов
/ 04 июня 2019

Это не DUPE, СПАСИБО

У меня есть эта хранимая процедура, которая ссылается на 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 голосов
/ 04 июня 2019

Синтаксис цикла курсора с динамическим SQL немного сложнее, чем без динамического SQL, но как только вы увидите несколько примеров, должно стать очевидным, как он работает.Простой пример из PL / SQL Руководство пользователя и справочник - 10g Release 1 (10.1) - Оператор OPEN-FOR-USING :

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: Открыть курсор с помощью оператора динамического выбора

Google покажет вам еще много примеров.Ищите 'динамический sql с открытым курсором оракула'.Еще один пример: Динамический SQL с курсором ссылки

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...