28 de febrero de 2003

TextMerge y SQL Pass Through (SPT) trabajando juntos

Cansado de codificar largas y tediosas instrucciones INSERT para utilizarlas via SPT?, aquí te decimos como hacerlo un poco mas fácil.

 En dias pasado se comentaba en los foros de noticias de Microsoft, si se podría utilizar la cláusula FROM MEMVAR dentro de sentencias enviadas via SQL Pass Through (SPT):
Select MiCursor

SCATTER MEMVAR

SQLExec(lnConnHandle,"INSERT INTO miTablaSQL FROM MEMVAR")

Esto no es posible, ya que nisiquiera el controlador ODBC de VFP da la posibilidad de hacerlo, ni hablar de cualquier otro cómo puede ser MS-SQL Server.

Claro está, la vistas remotas podría ser la solución, pero puede que el requisito para resolver cierto problemas (como el tener cientos de tablas, lo que nos tendría cientos de vistas creadas y quizás despues no se usaran) no nos permite hacerlo.

Por tal motivo propongo una idea para crear sentencias INSERT para ser enviadas via SPT. TextMerge puede ser una solución viable:
FUNCTION CrearInsert(tcCursor, tcTabla)
   LOCAL lnFields,; && Numero de campos del cursor
         laFields,; && Arreglo con la estructura del cursor
         lcInsertQuery && Cadena que contendrá el INSERT
   DIMENSION laFields[1]
   lcInsertQuery=SPACE(0)
   **** Hacemos algunas validaciones ****
   **** Si no se incluye el nombre del cursor o de la tabla
   **** Se utilizará el ALIAS() en ambos casos

   tcCursor = IIF(TYPE('tcCursor')#'C' OR EMPTY(tcCursor),ALIAS(), tcCursor)
   tcTabla  = IIF(TYPE('tcTabla') #'C' OR EMPTY(tcTabla),tcCursor,tcTabla)
   
   **** Obtenemos la información del cursor 
   lnFields = AFIELDS(laFields,tcCursor)
   IF lnFields > 0 
      **** Creamos la instrucción INSERT(Campo,Campo2...CampoN) ****
      SET TEXTMERGE ON
      SET TEXTMERGE TO MEMVAR lcInsertQuery NOSHOW 
    \  INSERT INTO << tcTabla >>(
      FOR I=1 TO lnFields
      \   << laFields[i,1] >>,
      ENDFOR
      SET TEXTMERGE TO
      lcInsertQuery=SUBSTR(lcInsertQuery,1,LEN(lcInsertQuery)-1) + ')'

      **** Agregamos la cláusula VALUES(?Campo1, ?Campo2... ?CampoN) ****
      SET TEXTMERGE TO MEMVAR lcInsertQuery NOSHOW ADDITIVE
     \  VALUES (
      FOR I=1 TO lnFields
       \  ?<< tcCursor >>.<< laFields[i,1] >>,
      ENDFOR
      SET TEXTMERGE TO
      SET TEXTMERGE OFF
      lcInsertQuery=SUBSTR(lcInsertQuery,1,LEN(lcInsertQuery)-1)+ ')'
   ENDIF
   RETURN lcInsertQuery
ENDFUNC


Muy bien, ya tenemos la función ahora veremos un caso práctico en el cual utilizarlo.
Supongamos que tenemos un numero indeterminado de tablas VFP cuyos registros serán insertadas al servidor de base de datos via SPT. Donde la tabla tiene la siguiente estructura:

MiTabla (iID int, dFecha date, iClienteID int, iSeccionID int, yImporte Y)

USE miTabla IN 0
lcInsert = CrearInsert("Mitabla","Ventas")


La cadena lcInsert contendrá lo siguiente:

INSERT INTO Ventas( IID, DFECHA, ICLIENTEID, ISECCIONID, YIMPORTE) VALUES(?MiTabla.IID,?MiTabla.DFECHA,?MiTabla.ICLIENTEID,?MiTabla.ISECCION,?MiTabla.YIMPORTE)

Ahora podemos utilizar esta instrucción para mandarla via SPT:

USE MiTabla IN 0
lcInsert = CrearInsert("Mitabla","Ventas")
lcRegistros = trans( RECCOUNT("MiTabla"))
llError = .F.
IF SQLPrepare(lnConnHandle,lcInsert) > 0
   SCAN FOR NOT llError
       WAIT WINDOW "Insertando registro " + TRANS(recno())+ "/"+lcRegistros NOWAIT
       llError = SQLExec(lnConnHandle) < 0
   ENDSCAN
    IF llError 
         Messagebox(laError[2],"Error al insertar")
    ELSE
      WAIT WINDOW "Proceso Finalizado"
    ENDIF
ENDIF

Lo anterior es un ejemplo sencillo donde quizas pueda hacerse manualmente, pero imagínate si dicha tabla(s) tienen 50 campos, o incluso, se tienen 100 tablas?, aquí es donde este proceso de crear Insert vía TEXTMERGE ayudará en demasía. Espero que este tip les sea de utilidad.

Espartaco Palma Martínez