miércoles, 16 de febrero de 2011

Script - Calculo_MD5_Consulta.sql

-- 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')"

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 ) ) );