 |
|
 |
BULK COLLECT
PL/SQL nos permite leer varios registros en una tabla de PL con un único acceso a través de la instrucción BULK COLLECT.
Esto nos permitirá reducir el número de accesos a disco, por lo que optimizaremos el rendimiento de nuestras aplicaciones. Como contrapartida el consumo de memoria será mayor.
DECLARE TYPE t_descripcion IS TABLE OF PAISES.DESCRIPCION%TYPE; TYPE t_continente IS TABLE OF PAISES.CONTINENTE%TYPE;
v_descripcion t_descripcion; v_continente t_continente; BEGIN SELECT DESCRIPCION, CONTINENTE BULK COLLECT INTO v_descripcion, v_continente FROM PAISES; FOR i IN v_descripcion.FIRST .. v_descripcion.LAST LOOP dbms_output.put_line(v_descripcion(i) || ', ' || v_continente(i)); END LOOP; END; / |
Podemos utilizar BULK COLLECT con registros de PL.
DECLARE TYPE PAIS IS RECORD (CO_PAIS NUMBER , DESCRIPCION VARCHAR2(50), CONTINENTE VARCHAR2(20)); TYPE t_paises IS TABLE OF PAIS;
v_paises t_paises; BEGIN SELECT CO_PAIS, DESCRIPCION, CONTINENTE BULK COLLECT INTO v_paises FROM PAISES; FOR i IN v_paises.FIRST .. v_paises.LAST LOOP dbms_output.put_line(v_paises(i).DESCRIPCION || ', ' || v_paises(i).CONTINENTE); END LOOP; END; / |
Tambien podemos utilizar el atributo ROWTYPE.
DECLARE TYPE t_paises IS TABLE OF PAISES%ROWTYPE;
v_paises t_paises; BEGIN SELECT CO_PAIS, DESCRIPCION, CONTINENTE BULK COLLECT INTO v_paises FROM PAISES; FOR i IN v_paises.FIRST .. v_paises.LAST LOOP dbms_output.put_line(v_paises(i).DESCRIPCION || ', ' || v_paises(i).CONTINENTE); END LOOP; END; / | |
| |
 |
BULK COLLECT y la clausula LIMIT
por
Henry Torres
Respuesta recibida el [18/04/2008 10:33:50]
|
 |
La cláusula LIMIT nos permite definir la cantidad de datos que vamos a colocar en memoria.
DECLARE TYPE t_paises IS TABLE OF PAISES%ROWTYPE;
v_paises t_paises; CURSOR cur_paises is SELECT CO_PAIS, DESCRIPCION, CONTINENTE;
BEGIN OPEN cur_paises LOOP FETCH cur_paises BULK COLLECT INTO v_paises LIMIT 100; FOR i IN 1 .. v_paises.COUNT LOOP dbms_output.put_line(v_paises(i).DESCRIPCION || ', ' || v_paises(i).CONTINENTE); END LOOP; END LOOP; END; /
Mientras mas pequeño en valor sera menos costoso en memoria.
|
| |
 |
Excelente aportación. Gracias ...
por
Devjoker
Respuesta recibida el [18/04/2008 12:49:58]
|
 |
Excelente aportación. Gracias Henry!
|
| |
 |
PLS-00597: expression in the INTO list is of wrong type
por
Gaspar Zapata
Respuesta recibida el [08/05/2008 01:28:27]
|
 |
Hola, realice una pruena y me envía un mensaje de error de la tabla me podrías ayudar estoy en oracle 8i este es mi código
Declare TYPE RegistroContrato IS RECORD ( NumeroCliente clientes_contratos.cli_no_cliente%TYPE, NumeroContrato clientes_contratos.no_contrato%TYPE, ClaveCargo Varchar2(3), ClaveProducto clientes_contratos.prd_cve_producto%TYPE, NumeroPaquete Number(10), FechaProgramada clientes_contratos.fecha_inicio%TYPE, FechaRegistro Date, ImporteCargo productos_cargos_contratos.IMPORTE_CARGO%TYPE ); TYPE TablaContratos IS TABLE OF RegistroContrato;
TContratos TablaContratos; begin dbms_output.put_line('Obtengo datos: '|| to_char(sysdate,'hh:mm:ss')); SELECT clientes_contratos.cli_no_cliente no_cliente, clientes_contratos.no_contrato contrato, 'AXT' clave_cargo, clientes_contratos.prd_cve_producto producto, TO_NUMBER (NULL) numero_paquete, clientes_contratos.fecha_inicio fecha_programada, TO_DATE (NULL) fecha_registro, productos_cargos_contratos.IMPORTE_CARGO importe BULK COLLECT INTO TContratos. FROM clientes_contratos, productos_cargos_contratos WHERE clientes_contratos.no_contrato = productos_cargos_contratos.cc_no_contrato AND productos_cargos_contratos.ptc_tcg_cve_cargo = 'AXT' AND NOT EXISTS ( SELECT 1 FROM set_tcargos_pendientes WHERE set_tcargos_pendientes.vcve_producto = clientes_contratos.prd_cve_producto AND set_tcargos_pendientes.nno_contrato = clientes_contratos.no_contrato AND set_tcargos_pendientes.vcve_cargo = 'AXT' AND TO_CHAR(set_tcargos_pendientes.dfecha_generacion,'YYYYMM') = TO_CHAR(sysdate,'YYYYMM')) AND (clientes_contratos.fecha_fin IS NULL OR clientes_contratos.fecha_fin > SYSDATE );
dbms_output.put_line('Leo los datos: '|| to_char(sysdate,'hh:mm:ss'));
FOR RS IN TContratos.FIRST .. TContratos.LAST LOOP dbms_output.put_line('Contrato: '|| TContratos(RS).NumeroContrato); END LOOP; dbms_output.put_line('Fin del proceos: '|| to_char(sysdate,'hh:mm:ss'));
end;
|
| |
 |
DUDA sobre Bulk collect
por
Alberto
Respuesta recibida el [02/07/2008 10:30:25]
|
 |
Por favor, alguien expliqueme con "manzanas" que hace especificamente el BULK COLLECT gracias
|
| |
 |
Manzanas para Alberto
por
alpedoteam
Respuesta recibida el [04/07/2008 10:20:08]
|
 |
Como es sabido, en plsql, cuando ejecutamos una consulta que retorna solamente como resultado una tupla o registro, podemos guardar el valor de dicha tupla en una(s) variable(s) usando la palabra reservada INTO
Ejemplo:
Declare ... campo1 tipo; ...
Begin .. Begin Select campo1 INTO val_campo1 from tablaX .. Where ... Exception ... End; .. End;
Sin embargo, el uso de INTO, no es posible cuando nuestra consulta retorna mas de una fila, y es necesario recurrir a otras opciones: 1. Una opción es recurrir a la definición de cursores 2. Una segunda alternativa es usar la palabra reservada BULK COLLECT en vez de INTO y por supuesto, ahora en vez de necesitar una variable necesitaremos de una estructura para guardar multiples registros.
Entrando en materia, veamos un ejemplo del uso de BULK COLLECT: Ejemplo No. 1
Creamos una tabla con dos campos
create table tablaX ( a number, b varchar2(10) );
Ahora llenamos la tabla con algunos valores:
insert into tablaX values (11,'lunes'); insert into tablaX values (12,'martes'); insert into tablaX values (13,'miercoles'); insert into tablaX values (14,'jueves');
commit;
Ahora veamos el plsql correspondiente. Se definirán dos tipos t_tablaX_a y t_tablaX_a de tipo tabla(aquí vale la redundancia) y se declara una variable para cada uno de estos tipos. En el cuerpo del bloque anónimo, Colocamos un SELECT con la opcion BULK COLLECT INTO para guardar los registros que retorna la consulta en las variables de tipo tabla.
set serveroutput on size 10000
Declare type t_tablaX_a is table of tablaX.a%type; type t_tablaX_b is table of tablaX.b%type;
var1 t_tablaX_a; var2 t_tablaX_b; Begin SELECT a, b BULK COLLECT INTO var1, var2 from tablaX;
for i in var1.first .. var1.last loop dbms_output.put_line(var1(i) || ', ' || var2(i)); end loop;
End;
Ejemplo No. 2
A diferencia del anterior ejemplo, en éste, dos variables son asignadas sólo a una variable. Esta variable debe ser del tipo table. Sin embargo, el tipo de los elementos en el tipo tabla deben ser de tipo Object con dos variables miembro que corresponden a las columnas seleccionadas. Otra diferencia es que la colección estará dentro de una función que retorne los valores.
Primero, creamos el tipo objeto.
create or replace type varchar_number as object ( v varchar2(10), i number ); /
Creamos ahora el tipo t_varchar_number de tipo tabla usando varchar_number como elementos
create or replace type t_varchar_number as table of varchar_number; /
Ahora creamos una tabla vn y guardamos algunos valores para nuestro ejemplo
create table vn ( v varchar2(10), i number );
insert into vn values ('uno',1); insert into vn values ('dos',2); insert into vn values ('tres',3);
commit;
Ahora, la siguiente función recoge los valores de la tabla vn y los retorna como una colección:
create or replace function fct_t return t_varchar_number as ret t_varchar_number; begin select varchar_number(v,i) bulk collect into ret from vn;
return ret; end; /
Finalmente dentro de un procedimiento anónimo llamamos la función que actuará como la colección y será recorrida dentro del loop.
set serveroutput on size 10000
Declare x t_varchar_number; Begin x := fct_t;
for r in (select * from table(cast(x as t_varchar_number))) loop dbms_output.put_line(r.v || ', ' || r.i); end loop;
End; / uno, 1 dos, 2 tres, 3
Gracias a ZonaOracle.
|
| |
 |
Consulta sobre Bulk Collect
por
Alexis Adrovez
Respuesta recibida el [14/08/2008 11:02:33]
|
 |
En SQL cuando queria mostrar o validar algunos datos, recorria X talba la validadaba y los datos erroneos los insertaba en una Tabla temporal.
Mi pregunta puedo simular lo mismo con este Bulk Collect.
Me explico mejore.
Tengo una talba llamada Facturas. Creo un Cursor para recorrer esta tabla y preguntar si cumple varias condiciones, si no la cumple inserto dicha fila en una tabla temporal.
AL final devuelvo la tabla temporan con un simple Select * From TablaTermporal el cual contiene los datos erroneos.
Se puede hacer algo perecido con Bulk Collect o algo en ORACLE.
|
| |
 |
Manejo de Excepciones - Consulta sobre Bulk Collect
por
Karen
Respuesta recibida el [14/08/2008 11:30:38]
|
 |
Hola a todos!, ...
Quisiera compartir mi experiencia con Uds del uso del Bulk Collect y a la vez realizar una consulta muy similar a la de Alexis,... Estoy trabajando en una Migración de Datos donde estamos filtrando y depurando datos de un servidor a otro, no es una vulgar copia de tablas, lo estabamos realizando mediando programas que implementaban Cursores y luego usando FOR... LOOP efectuabamos las inserciones en las tablas destino, pero al mover la gran cantidad de registros esto lleva mucho tiempo.
Buscando como optimizar nuestros programas de migración, encontramos el tema en cuestion, el Bulk Collect y nos hemos quedado con la boca abierta de ver la velocidad con la q hace la copia de la misma tabla de 80,000 en un par de segundos, cuando antes la trasladabamos en mas de 1hr, lo cual me parece grandioso.
Aun asi, mi consulta es muy similar a a la anterior, en el uso de Cursores y FOR... LOOP, cuando haciamos los INSERT manejabamos las excepciones o errores que pudieran darse a la hr de hacer las inserciones usando WHEN DUP_VAL_ON_INDEX, WHEN NO_DATA_FOUND & WHEN OTHERS - RAISE EXEC_ERROR; capturando estos errores e insertandolos en una tabla log creada para monitorear esos problemas.
Como podria implementar los EXCEPTION dentro de esta estructura :
BEGIN
OPEN c_Cliente_Siniestro;
get_time(t1);
LOOP
FETCH c_Cliente_Siniestro BULK COLLECT INTO l_data;
FORALL i IN 1..l_data.COUNT
INSERT INTO MIGRA9I.CLIENTE VALUES l_data(i); EXIT WHEN c_Cliente_Siniestro%NOTFOUND;
END LOOP;
get_time(t2);
CLOSE c_Cliente_Siniestro;
Commit;
--** Contando los registros insertados Select count(*) into Regs from migra9i.CLIENTE where producto = 'SINA';
DBMS_OUTPUT.PUT_LINE('Se Grabaron ' || TO_CHAR(Regs)||' en un tiempo de '|| TO_CHAR(t2 - t1));
END;
... Alguien tiene una idea de como puedo implementar el EXCEPTION usando Bulk Collect?
:) Gracias y espero sus prontos comentarios!!
|
| |
 |
si como dijo la amiga Karen si...
por
Humberto
Respuesta recibida el [26/08/2008 12:07:48]
|
 |
si como dijo la amiga Karen si alguien sabria como manjar las excepciones usando bulk collect se los agradeceria
|
| |
 |
Pregunta de principiantes
por
DubkelBlume
Respuesta recibida el [29/08/2008 12:09:25]
|
 |
Una pregunta muy ... tonta ~_~
como hago saltos de línea en PL/SQL, cuando presento la información, para que no este todo en una sola línea, estoy es lo que tengo de código
DECLARE
TYPE arrEstu IS TABLE OF ESTUDIANTES%ROWTYPE; students arrEstu; v_rows NUMBER:=0;
BEGIN select count(*)INTO v_rows from ESTUDIANTES;
SELECT ID,NOMBRE,APELLIDO,ESPECIALIDAD,CREDITOS BULK COLLECT INTO students FROM PRUEBA.ESTUDIANTES; FOR i IN 1..v_rows LOOP htp.print(students(i).ID||' '||students(i).NOMBRE||' '||students(i).APELLIDO||''); END LOOP; END;
es cosa bien simple, pero alguien me puede ayudar???
|
| |
 |
Opción util
por
DubkelBlume
Respuesta recibida el [29/08/2008 01:00:17]
|
 |
Pues encontre que es más útil, para mi, utilizar HTML para presentar la información y es que estoy haciendo reportes en un portal, usando OracleAS Portal
|
| |
 |
Manejo de Excepciones
por
Henry Torres
Respuesta recibida el [12/09/2008 08:56:11]
|
 |
Haber si esto los ayuda, pero en realidad no es nada complicado.
DECLARE
-- DECLAREMOS LAS VARIABLES A UTILIZAR errors PLS_INTEGER; array_dml EXCEPTIONS; PRAGMA EXCEPTION_INIT(dml_errors, -24381);
BEGIN
OPEN c_Cliente_Siniestro;
get_time(t1);
LOOP
FETCH c_Cliente_Siniestro BULK COLLECT INTO l_data;
FORALL i IN 1..l_data.COUNT SAVE EXCEPTIONS -- SI OCURRE ALGUN ERROR EL INSERT NO SE DETENDRA
INSERT INTO MIGRA9I.CLIENTE VALUES l_data(i); EXIT WHEN c_Cliente_Siniestro%NOTFOUND; END LOOP;
EXCEPTION WHEN dml_errors THEN errors := SQL%BULK_EXCEPTIONS.COUNT; dbms_output.put_line('Cantidad de registros que fallaron: ' || errors);
FOR i IN 1 .. errors LOOP dbms_output.put_line('Error #' || i || ' at '|| 'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX); dbms_output.put_line('Error message is ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE)); END LOOP; WHEN OTHERS THEN RAISE; get_time(t2);
CLOSE c_Cliente_Siniestro;
|
| |
 |
Velocidad del query con BULK COLLECT
por
Pako Silva
Respuesta recibida el [25/09/2008 10:42:18]
|
 |
Hola...
Veo que hablan que el BULK COLLECT mejora la velocidad de una sentencia que haciendo el recorrido de un cursor, tengo la duda si esto mejora tambien el tiempo de respuesta, por ejemplo yo tengo un cursor que extrae datos de clientes con facturas sin pagar, para extraer solo los clientes con facturas abiertas voy guardando en una tabla temporal los datos que voy extrayendo con el cursor, el bulk collect de que manera mejora el rendimiento si solo es en el recorrido del cursor o tambien en su ejecucion, ya que normalmente no manejo mas de 20 registros de vuelta que se guardan en la tabla temporal.
|
| |
 |
respuesta para saltos de linea
por
hansell ramos
Respuesta recibida el [18/10/2008 02:54:41]
|
 |
sparecera tonto pero para saltos de linea en plsql solo debes escribir el salto de linea asi
dbms_output.put_line(' ');
|
| Añadir comentario ... |
Para preguntar utiliza los foros
|
|

|
BULK COLLECT |
|
Autor:
Pedro Herrarte Sánchez
|
|
Visitas:
24543 |
Fecha de publicación:
21/02/2007 |
Pedro Herrarte, es consultor independiente, ofreciendo servicios de consultoría, análisis, desarrollo y formación.
Posee mas de diez años de experiencia trabajando para las principales empresas de España.
Es especialista en tecnologías .NET, entornos Web, bases de datos (SQL Server y ORACLE) e integración de sistemas.
Es experto en desarrollo (C#, ASP.NET, VB.Net, T-SQL, PL/SQL, , ASP, CGI , C, Pro*C, Java, Essbase, Vignette, PowerBuilder y Visual Basic ...) y bases de datos (SQL Server y ORACLE).
Es fundador, diseñador y programador de www.devjoker.com. |
|
|
Visitas:
35
|
Comentarios:
0
|
Archivo:
Articulos
|
|
Visitas:
108
|
Comentarios:
0
|
Archivo:
Articulos
|
Visitas:
155
|
Comentarios:
0
|
Archivo:
Articulos
|
Visitas:
33
|
Comentarios:
0
|
Archivo:
Articulos
|
Visitas:
285
|
Comentarios:
1
|
Archivo:
Articulos
|
Visitas:
839
|
Comentarios:
2
|
Archivo:
Articulos
|
Visitas:
712
|
Comentarios:
1
|
Archivo:
Articulos
|
Visitas:
447
|
Comentarios:
0
|
Archivo:
Articulos
|
Visitas:
1052
|
Comentarios:
1
|
Archivo:
Articulos
|
Visitas:
250
|
Comentarios:
0
|
Archivo:
Articulos
|
|
|
|
 |
| Encuesta |
|
¿A que perfil te adaptas mejor? |
|
|
|
|
|
|
|
|
 |