InicioArticulos y noticiasBases de datosProgramaciónForosInternetServiciosContratacionEmail
Tutorial PL/SQL
Introducción a PLSQL
Programación con PL/SQL
Fundamentos de PL/SQL
Tipos de datos en PL/SQL
Operadores en PL/SQL
Estructuras de control en PL/SQL
Bloques PL/SQL
Cursores en PL/SQL
Cursores Implicitos en PL/SQL
Cursores Explicitos en PL/SQL
Cursores de actualización en PL/SQL
Excepciones en PL/SQL
Excepciones personalizadas en PL/SQL
Propagacion de excepciones en PL/SQL
Subprogramas en PL/SQL
Procedimientos almacenados en PL/SQL
Funciones en PL/SQL
Triggers en PL/SQL
Subprogramas en bloques anónimos
Paquetes en PL/SQL
Registros PL/SQL
Tablas PL/SQL
Tipo VARRAY
BULK COLLECT
Transacciones con PL/SQL
Transacciones autónomas
SQL Dinamico
Funciones integradas de PL/SQL
Secuencias
PL/SQL y Java
SQL
  Tutorial SQL
SQL Server
  Tutorial de Transact-SQL
ORACLE
  Tutorial PL/SQL
.NET
  Introducción a.NET
  Conceptos generales .NET
  Tutorial C#
  LinQ
  WCF
Reina Roja
  Humor
  Bibliografia
  Acerca de ...

Afiliados
La Web del programador
MundoProgramacion


 

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


Inicio | Tutorial PL/SQL Tipo VARRAYTutorial PL/SQLTransacciones con PL/SQL Versión para imprimir Foros de consulta

 
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
Autor:

Título:


Para preguntar utiliza los foros.



Inicio | Tutorial PL/SQL Tipo VARRAYTutorial PL/SQLTransacciones con PL/SQL Versión para imprimir

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
Categorias: ASP.NET
Visitas: 33 | Comentarios: 0 | Archivo: Articulos
Categorias: TFS
Visitas: 285 | Comentarios: 1 | Archivo: Articulos
Categorias: Visual Basic .NET|C#
Visitas: 839 | Comentarios: 2 | Archivo: Articulos
Categorias: C#|ASP.NET|HTML DHTML|XML|JavaScript|ASP.NET|ASP|PHP|Visual Studio
Visitas: 712 | Comentarios: 1 | Archivo: Articulos
Categorias: Administración|Tutorial SQL
Visitas: 447 | Comentarios: 0 | Archivo: Articulos
Categorias: ASP.NET
Visitas: 1052 | Comentarios: 1 | Archivo: Articulos
Categorias: ASP.NET|CSS|ASP.NET
Visitas: 250 | Comentarios: 0 | Archivo: Articulos
Categorias: TFS

Útimos temas recibidos en los foros ...
FORMULARIO ACCESS por jcifuentes ... [Access] 11 29/05/2007
Ysmael por Ysmael ... [SQL] 0 08/01/2009
Reflection por Maurito22 ... [C#] 2 06/01/2009
Programador por Robert ... [ORACLE] 0 07/01/2009
como insertar registros en un formulario de visual basic.net desde la base de datos sql server por orlan ... [SQL Server] 8 09/06/2008
quierocodigo de autogenerado del seguro por edwin garcia ramirez ... [Visual Basic .NET] 0 07/01/2009
Video gratis sobre AJAX con ASP.NET por alexxe ... [ASP.NET] 1 06/01/2009
calcular saldo acumulativo por cben ... [SQL] 5 30/12/2008
comparar 2 campos de 2 tablas usando el like por nani ... [SQL Server] 1 06/01/2009
Apagar ordenador remoto en C# por victoryiyo ... [C#] 1 07/01/2009
numero de AUTOGENERADO IPSS por carlos ... [Visual Basic .NET] 5 30/10/2008
Como mandar mensaje a Celular por Pako ... [C#] 63 13/03/2007

Access CGI JSP ORACLE UNIX
Actualidad HTML/DHTML/XHTML LINUX PHP Visual Basic .NET
ASP ISAPI MS DOS Power Builder Visual Basic 6.0
ASP.NET Java mySQL SQL WIN 98/NT/2000/XP
C# JavaScript Opinion SQL Server

devjoker  Te recomendamos además ...
01/01/2006 Consultas agregadas    forma parte de...Tutorial SQL
19/10/2005 Una clase sencilla para encriptar cadenas
19/09/2006 Recuperar datos BLOB de ORACLE
11/09/2006 Trabajar con datos de tipo BLOB en ORACLE
24/05/2006 Cursores Implicitos en PL/SQL    forma parte de...Tutorial PL/SQL
29/09/2006 Common Language Specification (CLS)    forma parte de...Conceptos generales .NET
30/12/2007 Mas plantillas Web - TemplateMonster
29/09/2006 Common Type System (CTS)    forma parte de...Conceptos generales .NET
23/05/2006 Cursores en PL/SQL    forma parte de...Tutorial PL/SQL
29/09/2006 Librería de clases    forma parte de...Conceptos generales .NET

 

Encuesta
¿A que perfil te adaptas mejor?
[Ver] [Votar]