Curso de C++ Builder


Acceso a bases de datos

TStoredProc



El componente TStoredProc representa un procedimiento almacenado en un servidor de bases de datos. El esquema de utilización de procedimientos almacenados es:

Procedimientos almacenados que devuelven valores

create procedure EstadisticasProducto (CodProd int)
                 returns ( TotalPedidos int, CantidadTotal int,
                           TotalVentas int,  TotalClientes int )
as
  declare variable Precio int;

begin

  select Precio
  from Articulos
  where Codigo = :CodProd
  into :Precio;

  select count(Numero), count(distinct RefCliente)
  from Pedidos
  where :CodProd 
        in ( select RefArticulo
             from Detalles
             where RefPedido = Numero )
  into :TotalPedidos, :TotalClientes;

  select sum(Cantidad), sum(Cantidad*:Precio*(100-Descuento)/100)
  from Detalles
  where Detalles.RefArticulo = :CodProd
  into :CantidadTotal, :TotalVentas;

end ^


void __fastcall ...::EstadisticasProducto(TObject *Sender)
{
  AnsiString S;

  if ( InputQuery("Información", "Código del producto", S) 
       && Trim(S) != "" ) {

     TStoredProc *sp = DataModuleProductos->spEstadisticas;

     sp->ParamByName("CodProd")->AsString = S;

     sp->ExecProc();

     ShowMessage( Format( "Pedidos: %d\nClientes: %d\nCantidad: %d\nTotal: %m",
                  ARRAYOFCONST((sp->ParamByName("TotalPedidos")->AsInteger,
                                sp->ParamByName("TotalClientes")->AsInteger,
                                sp->ParamByName("CantidadTotal")->AsInteger,
                                sp->ParamByName("TotalVentas")->AsFloat))));
  }
}

Procedimientos almacenados que devuelven conjuntos de datos

Definimos una base de datos (en InterBase) para almacenar una jerarquía de conceptos (como las categorías de un índice en Internet tipo Yahoo!):

create domain TID as INTEGER;
create domain TDESCRIPTION as VARCHAR(128);


create table CATEGORY (
  ID          TID not null,
  description TDESCRIPTION,
  primary key (ID) );

create table HIERARCHY (
  SUPER   TID not null references CATEGORY, 
  SUB     TID not null references CATEGORY,
  primary key (SUPER,SUB) );

Creamos sendos procedimientos almacenado recursivos que nos devuelven todas las categorías por debajo (o por encima) de una categoría dada en la jerarquia:

create procedure DESCENDANTS (super integer)
  returns (sub integer)
as
begin

 FOR SELECT sub
     FROM HIERARCHY
     WHERE SUPER = :super
     INTO :sub
 DO BEGIN

     if (sub is not null)
        then begin
               SUSPEND;
	       for select *
	           from DESCENDANTS(:sub)
		   into :sub
	       do begin
		   if (sub is not null)
		      then SUSPEND;
	       end
	     end
    END

end ^


create procedure ANCESTORS (sub integer)
  returns (super integer)
as
begin

 FOR SELECT id
     FROM HIERARCHY
     WHERE SUB = :sub
     INTO :super
 DO BEGIN

     if (super is not null)
        then begin
               SUSPEND;
	       for select *
	           from ANCESTORS(:super)
		   into :super
	       do begin
		   if (super is not null)
		      then SUSPEND;
	       end
	     end
    END

end ^

set term ;^

Para utilizar los procedimientos almacenados anteriores, se puede escribir alguna de las siguientes consultas parametrizadas en la propiedad SQL de un TQuery:

select distinct * from descendants(:id)

select distinct * from ancestors(:id)

Ejecución de un procedimiento almacenado en una hebra independiente

class TSPThread : public TThread
{
 protected:
  void __fastcall Execute();
 public:
  __fastcall TSPThread();
};

__fastcall TSPThread::TSPThread():TThread(True) // Crear hebra "suspendida"
{
  FreeOnTerminate = True;
  Resume(); // Ejecutar la hebra
}

// DataModuleSPThread es un módulo de datos con tres componentes:
// - SessionSPThread (de tipo TSession),
// - DatabaseSPThread (de tipo TDatabase), y
// - StoredProcSPThread (de tipo TStoredProc).

void __fastcall TSPThread::Execute()
{
  DataModuleSPThread->DatabaseSPThread->Open();

  try {
      DataModuleSPThread->StoredProcSPThread->ExecProc();
  } __finally {
      DataModuleSPThread->SessionSPThread->Close();
  }
}

// Ejecución

void __fastcall TForm1::Btn1Click(TObject *Sender)
{
  new TSPThread;
}


Índice de la sección