-- Función para el cálculo MD5 de una consulta pasada como parámetro:
create or replace function hash_sql(l_query varchar2) return varchar2
is
pragma autonomous_transaction;
l_theCursor integer default dbms_sql.open_cursor;
l_columnValue varchar2(32000);
l_status integer;
l_colCnt number := 0;
l_separator varchar2(1);
l_descTbl dbms_sql.desc_tab;
l_i number:=0;
l_data CLOB:='';
l_checksum CLOB:='';
begin
execute immediate 'alter session set nls_date_format=''dd/mm/yyyy hh24:mi:ss'' ';
dbms_sql.parse( l_theCursor, l_query, dbms_sql.native );
dbms_sql.describe_columns( l_theCursor, l_colCnt, l_descTbl );
for i in 1 .. l_colCnt loop
dbms_sql.define_column( l_theCursor, i, l_columnValue, 32000 );
end loop;
l_status := dbms_sql.execute(l_theCursor);
while ( dbms_sql.fetch_rows(l_theCursor) > 0 ) loop
for i in 1 .. l_colCnt loop
dbms_sql.column_value( l_theCursor, i, l_columnValue );
l_i:=i;
l_data:=l_data||trim(TO_CHAR(l_columnValue));
end loop;
end loop;
dbms_sql.close_cursor(l_theCursor);
rollback;
return dbms_crypto.hash( src => l_data, typ=>dbms_crypto.hash_md5 );
exception
when others then
return 'ERROR';
end;
/
-- Llamada:
select hash_sql ('SELECT * FROM tabla where columna='||CHR(39)||'VALOR'||CHR(39)||' order by 1 ') md5 from dual
/
-- Funcionamiento/Restricciones:
A) Se basa en el uso del paquete DBMS_CRYPTO de Oracle (ver > 10g)
B) El cálculo MD5 ser realiza sobre la concatenación de todas las columnas devueltas por la consulta y concatenación fila a fila de los resultados, por ejemplo:
column1 column2
------- -------
a b
a2 b2
La cadena sobre la que se aplica el MD5 sería:
"aba2b2"
C) Cada valor de cada fila / columna se convierte en texto y se eliminan espacio finales e iniciales (TRIM(TO_CHAR(...))
D) El formato para la conversión de datos tipo fecha es: "dd/mm/yyyy hh24:mi:ss"
E) Es importante que las consultas tengan una ordenación (Ej.- "ORDER BY NLSSORT(VAL_ELE_COD, 'NLS_SORT = BINARY')"
miércoles, 16 de febrero de 2011
lunes, 7 de febrero de 2011
Script - DML Paralelo (pipelined funcition + bulk DML)
Extraído de : http://www.asktherealtom.ch/?p=94
-- Tabla de ejemplo
CREATE TABLE TRANSACTION(TRANSACTION_ID NUMBER, PRUEBA VARCHAR2(100)) TABLESPACE ...;
CREATE INDEX I_PK_TRANSID ON TRANSACTION(TRANSACTION_ID) TABLESPACE ...;
-- Rellenamos la tabla
INSERT INTO TRANSACTION SELECT ... FROM ... WHERE ROWNUM <=100000;
CREATE OR REPLACE PACKAGE PKG_PARALLEL AS
TYPE t_parallel_test_row IS RECORD ( TRANSACTION_ID NUMBER(16));
TYPE t_parallel_test_ref_cursor IS REF CURSOR RETURN t_parallel_test_row;
TYPE t_dml_counter IS TABLE OF NUMBER;
TYPE t_TRANSACTIONID_tab IS TABLE OF transaction.TRANSACTION_ID%TYPE INDEX BY BINARY_INTEGER;
v_row1 t_TRANSACTIONID_tab;
v_array_size PLS_INTEGER := 500000;
function ptf_dml(p_cursor IN t_parallel_test_ref_cursor)
return t_dml_counter
pipelined
parallel_enable (PARTITION p_cursor BY ANY );
--parallel_enable (PARTITION p_cursor BY RANGE (TRANSACTIONID));
END PKG_PARALLEL;
/
SHOW ERRORS
CREATE OR REPLACE PACKAGE BODY PKG_PARALLEL AS
--create or replace function ptf_dml(p_cursor IN SYS_REFCURSOR)
function ptf_dml(p_cursor IN t_parallel_test_ref_cursor)
return t_dml_counter
pipelined
-- parallel_enable (PARTITION p_cursor BY RANGE (TRANSACTIONID))
parallel_enable (PARTITION p_cursor BY ANY )
is
PRAGMA AUTONOMOUS_TRANSACTION;
r_rowid transaction.TRANSACTION_ID%type;
BEGIN
LOOP
FETCH p_cursor BULK COLLECT INTO v_row1 LIMIT v_array_size;
FORALL i IN 1..v_row1.COUNT
UPDATE transaction t
SET t.PRUEBA = T.PRUEBA||'A'
WHERE TRANSACTION_ID=v_row1(i);
-- rollback;
commit;
pipe row (1);
EXIT WHEN p_cursor%NOTFOUND;
END LOOP;
end ptf_dml;
end PKG_PARALLEL;
/
SHOW ERRORS
alter session force parallel query parallel 4;
select count(*) from table(PKG_PARALLEL.ptf_dml( cursor(select /*+ PARALLEL(t,4) PARALLEL_INDEX(t, I_PK_TRANSID, 4) */ TRANSACTION_ID from TRANSACTION t ) ) );
-- Tabla de ejemplo
CREATE TABLE TRANSACTION(TRANSACTION_ID NUMBER, PRUEBA VARCHAR2(100)) TABLESPACE ...;
CREATE INDEX I_PK_TRANSID ON TRANSACTION(TRANSACTION_ID) TABLESPACE ...;
-- Rellenamos la tabla
INSERT INTO TRANSACTION SELECT ... FROM ... WHERE ROWNUM <=100000;
CREATE OR REPLACE PACKAGE PKG_PARALLEL AS
TYPE t_parallel_test_row IS RECORD ( TRANSACTION_ID NUMBER(16));
TYPE t_parallel_test_ref_cursor IS REF CURSOR RETURN t_parallel_test_row;
TYPE t_dml_counter IS TABLE OF NUMBER;
TYPE t_TRANSACTIONID_tab IS TABLE OF transaction.TRANSACTION_ID%TYPE INDEX BY BINARY_INTEGER;
v_row1 t_TRANSACTIONID_tab;
v_array_size PLS_INTEGER := 500000;
function ptf_dml(p_cursor IN t_parallel_test_ref_cursor)
return t_dml_counter
pipelined
parallel_enable (PARTITION p_cursor BY ANY );
--parallel_enable (PARTITION p_cursor BY RANGE (TRANSACTIONID));
END PKG_PARALLEL;
/
SHOW ERRORS
CREATE OR REPLACE PACKAGE BODY PKG_PARALLEL AS
--create or replace function ptf_dml(p_cursor IN SYS_REFCURSOR)
function ptf_dml(p_cursor IN t_parallel_test_ref_cursor)
return t_dml_counter
pipelined
-- parallel_enable (PARTITION p_cursor BY RANGE (TRANSACTIONID))
parallel_enable (PARTITION p_cursor BY ANY )
is
PRAGMA AUTONOMOUS_TRANSACTION;
r_rowid transaction.TRANSACTION_ID%type;
BEGIN
LOOP
FETCH p_cursor BULK COLLECT INTO v_row1 LIMIT v_array_size;
FORALL i IN 1..v_row1.COUNT
UPDATE transaction t
SET t.PRUEBA = T.PRUEBA||'A'
WHERE TRANSACTION_ID=v_row1(i);
-- rollback;
commit;
pipe row (1);
EXIT WHEN p_cursor%NOTFOUND;
END LOOP;
end ptf_dml;
end PKG_PARALLEL;
/
SHOW ERRORS
alter session force parallel query parallel 4;
select count(*) from table(PKG_PARALLEL.ptf_dml( cursor(select /*+ PARALLEL(t,4) PARALLEL_INDEX(t, I_PK_TRANSID, 4) */ TRANSACTION_ID from TRANSACTION t ) ) );
Suscribirse a:
Entradas (Atom)