Trabajar con cursores

Respuesta de
a
Usuario
Saludos, colabórenme por favor, ¿Se puede realizar un append from a un cursor? Como lo hago

Ejm, Select Campo1, campo2, campo3
from tabla1
where condiciones, condiciones2
into cursor a1

Use tabla2

¿append from?

Necesito adicionar el cursor a1
Avatar
Experto
Hola tu mail para enviarte el ejemplo
Avatar
Experto
Hola espero que esto te sirva

mi correo es alfalfa2007@hotmail.com

Note olvides de cerrar la pregunta

Utilizar un Select seguro
Un problema común al trabajar con cursores locales en VFP es que cuando ellos se utilizan como origen para controles Grid, la recreación del cursor provoca que el grid pierda parte o toda su configuración. La razón por la que esto ocurre es que cada vez que se ejecuta una sentencia SQL en VFP, el cursor destino existente se cierra, se elimina y se recrea. Como consecuencia, los datos del cursor se pierden y el grid pierde su enlace.
Esto es fácilmente demostrable, considerando lo siguiente:
*** Ejecutar un select básico a un cursor
SELECT * FROM account INTO CURSOR JUNK NOFILTER
? DBF('junk') && Returns F:\TEMP\00002PL5008K.TMP
*** Repetir la consulta
SELECT * FROM account INTO CURSOR JUNK NOFILTER
? DBF('junk') && Returns F:\TEMP\00002PL500AQ.TMP
Como puede ver, la segunda ejecución de la consulta crea un cursor nuevo que se abre con el mismo alias que el primero. Una comprobación rápida al disco mostrará que el primer cursor ha sido efectivamente eliminado. La consecuencia para el grid es que tiene que reconstruirse por si mismo desde el principio. Entonces, elimina todas las columnas existentes y crea nuevas columnas para el nuevo origen de datos. El resultado es, por supuesto, que todas las configuraciones específicas de las columnas se pierden y si el grid emplea columnas personalizadas o los controles han sido reemplazados por clases propias (o, desde la introducción de las clases member, en cualquier lugar que exista una clase member.) Por tanto, cualquier configuración específica se pierde y tiene que ser re-creada. ¡Esto, no es bueno!
Una solución al problema, que ofrezco con frecuencia en los foros on-line, es establecer la propiedad RecordSource del grid a una cadena vacía antes de hacer la consulta y resturarlo luego de realizada, algo así:
*** Guardar el contenido de la propiedad RecordSource y limpiarla
WITH ThisForm.Grid
lcBoundTo = .RecordSource
.RecordSource = ''
*** Ejecutar la nueva consulta
SELECT <fields> FROM <table> INTO CURSOR <recordsource>
.RecordSource = lcBoundTo
endwith
Y esto trabaja bien, permitiendo que el grid muestre las columnas en el orden natural.
La razón para esta salvedad es que lo que ocurre en realidad en este caso es que al limpiar la propiedad RecordSource del grid, se limpia también la propiedad ControlSource para cada columna. Cuando el grid es re-enlazado a un alias nuevo no tiene especificado el ControlSource de cada columna y el resultado es que el grid muestra ahora los datos basados en la posición del RecordSource. La primera columna muestra la primera columna del origen de datos, la segunda columna muestra la 2da y así sucesivamente.
Generalmente lo que sucede a continuación es que la persona que ha preguntado, trata la solución ofrecida, encuentra que su grid está completamente revuelto y regresa al foro preguntando ¿y ahora que hago? El siguiente paso suele ser sugerirle que cambie enteramente su metodología y que sustituya el cursor por una vista parametrizada. Esto es perfectamente válido y una vista parametrizada trabajará muy bien para estos casos.
Sin embargo, las vistas parametrizadas tienen una seria limitación. Debido a que las vistas deben estar pre-definidas, no es fácil crear una vista que acepte una condición de filtro para un propósito específico y es precisamente este requerimiento el que lleva a los desarrolladores a emplear, en primer lugar, un cursor. Por ejemplo, en una pantalla de registro de clientes el requerimiento es permitir al usuario que especifique cualquier combinación de First Name, LastName, Social Security Number, City, State, Order Number. Construir una vista parametrizada para controlarlo sería difícil, sino imposible.
Una solución para este problema es la técnica conocida como "select seguro".
La idea, es que debido a que los cursores se crean siempre en la estación de trabajo local del usuario, y se abren siempre en exclusivo, podemos utilizar el comando ZAP para limpiar, sin cerrar, un cursor. Entonces, en lugar de correr una consulta directamente sobre un cursor de trabajo emplearemos un cursor intermedio (o "fantasma") como destino para la consulta y agregamos simplemente el resultado al cursor de trabajo. He aquí el código para el "select seguro".
*** Crear un cursor de trabajo
SELECT * FROM account WHERE 0 = 1 INTO CURSOR curacct READWRITE
*** Ahora ejecutar la consulta real
SELECT * FROM account WHERE name LIKE 'Sm%' INTO CURSOR curdummy
*** Limpiar el cursor de trabajo y agregar el resultado.
SELECT curacct
ZAP IN curacct
APPEND FROM DBF('curdummy')
USE IN curDummy
Debido a que el cursor de trabajo no se cierra nunca, no hay ningún efecto sobre ningún control (incluyendo grids) que utilice el cursor como origen de datos. Esta técnica nos permite mantener la flexibilidad de un cursor sin los efectos secundarios indeseados causados por las repetidas aperturas y cierres de las re-consultas. Por supuesto, si tiene que escribir este código cada vez que desea re-crear un cursor podría ser bastante tedioso; pero tenemos un entorno completamente orientado a objeto en VFP, porqué no agregar un método a su formulario base que acepte dos parámetros - la cadena para la consulta y el nombre del cursor destino. Entonces, el código queda bien encapsulado y está disponible en cualquier forma que lo necesitemos. Puede incluso completar el código de tal forma que si el cursor destino no existe, sea creado por este método. He aquí mi método base "SaveSelect" con el que espero recibir una cadena de consulta que NO incluya una cláusula INTO - esto se agrega aquí:
LPARAMETERS tcSql, tcAlias
LOCAL lnSelect, lcSql
*** Guardar el área de trabajo
lnSelect = SELECT(0)
*** No existe el cursor
IF NOT USED( tcAlias )
*** Crearlo directamente
lcSql = tcSql + " INTO CURSOR " + tcAlias + " READWRITE"
&lcSql
ELSE
*** El cursor existe, utilizo un select seguro
lcSql = tcSql + " INTO CURSOR curdummy"
&lcSql
*** Limpiar y actualizar el cursor de trabajo
SELECT (tcAlias)
ZAP IN (tcAlias)
APPEND FROM DBF('curdummy')
USE IN curdummy
ENDIF
*** Restablecer el área de trabajo y devolver el estado
SELECT (lnSelect)
RETURN USED(tcAlias)


Atentamente.fitocava
Avatar
Experto
Otra tío
Exportar Cursor VFP a EXCEL
********************************************************************
********************************************************************
*!* FUNCTION Exp2Excel( [cCursor, [cFileSave, [cTitulo]]] )
*!*
*!* Exporta un Cursor de Visual FoxPro a Excel, utilizando la
*!* técnica de importación de datos externos en modo texto.
*!*
*!* PARAMETROS OPCIONALES:
*!* - cCursor Alias del cursor que se va a exportar.
*!* Si no se informa, utiliza el alias
*!* en que se encuentra.
*!*
*!* - cFileName Nombre del archivo que se va a grabar.
*!* Si no se informa, muestra el libro generado
*!* una vez concluída la exportación.
*!*
*!* - cTitulo Titulo del informe. Si se informa, este
*!* ocuparía la primera file de cada hoja del libro.
********************************************************************
********************************************************************
FUNCTION Exp2Excel( cCursor, cFileSave, cTitulo )
LOCAL cWarning
cWarning = "Exportar a EXCEL"
IF EMPTY(cCursor)
cCursor = ALIAS()
ENDIF
IF TYPE('cCursor') # 'C' OR !USED(cCursor)
MESSAGEBOX("Parámetros Inválidos",16,cWarning)
RETURN .F.
ENDIF
*********************************
*** Creación del Objeto Excel ***
*********************************
WAIT WINDOW 'Abriendo aplicación Excel.' NOWAIT NOCLEAR
oExcel = CREATEOBJECT("Excel.Application")
WAIT CLEAR

IF TYPE('oExcel') # 'O'
MESSAGEBOX("No se puede procesar el archivo porque no tiene la aplicación" ;
+ CHR(13) + "Microsoft Excel instalada en su computador.",16,cWarning)
RETURN .F.
ENDIF

oExcel.workbooks.ADD

LOCAL lnRecno, lnPos, lnPag, lnCuantos, lnRowTit, lnRowPos, i, lnHojas, cDefault

cDefault = ADDBS(SYS(5) + SYS(2003))

SELECT (cCursor)
lnRecno = RECNO(cCursor)
GO TOP

*************************************************
*** Verifica la cantidad de hojas necesarias ***
*** en el libro para la cantidad de datos ***
*************************************************
lnHojas = ROUND(RECCOUNT(cCursor)/65000,0)
DO WHILE oExcel.Sheets.COUNT < lnHojas
oExcel.Sheets.ADD
ENDDO

lnPos = 0
lnPag = 0

DO WHILE lnPos < RECCOUNT(cCursor)

lnPag = lnPag + 1 && Hoja que se está procesando

WAIT WINDOWS 'Exportando cursor ' + UPPER(cCursor) + ' a Microsoft Excel...' ;
+ CHR(13) + '(Hoja ' + ALLTRIM(STR(lnPag)) + ' de ' + ALLTRIM(STR(lnHojas)) ;
+ ')' NOCLEAR NOWAIT

IF FILE(cDefault + cCursor + ".txt")
DELETE FILE (cDefault + cCursor + ".txt")
ENDIF

COPY NEXT 65000 TO (cDefault + cCursor + ".txt") DELIMITED WITH CHARACTER ";"
lnPos = RECNO(cCursor)

oExcel.Sheets(lnPag).SELECT

XLSheet = oExcel.ActiveSheet
XLSheet.NAME = cCursor + '_' + ALLTRIM(STR(lnPag))

lnCuantos = AFIELDS(aCampos,cCursor)

********************************************************
*** Coloca título del informe (si este es informado) ***
********************************************************
IF !EMPTY(cTitulo)
XLSheet.Cells(1,1).FONT.NAME = "Arial"
XLSheet.Cells(1,1).FONT.SIZE = 12
XLSheet.Cells(1,1).FONT.BOLD = .T.
XLSheet.Cells(1,1).VALUE = cTitulo
XLSheet.RANGE(XLSheet.Cells(1,1),XLSheet.Cells(1,lnCuantos)).MergeCells = .T.
XLSheet.RANGE(XLSheet.Cells(1,1),XLSheet.Cells(1,lnCuantos)).Merge
XLSheet.RANGE(XLSheet.Cells(1,1),XLSheet.Cells(1,lnCuantos)).HorizontalAlignment = 3
lnRowPos = 3
ELSE
lnRowPos = 2
ENDIF

lnRowTit = lnRowPos - 1
**********************************
*** Coloca títulos de Columnas ***
**********************************
FOR i = 1 TO lnCuantos
lcName = aCampos(i,1)
lcCampo = ALLTRIM(cCursor) + '.' + aCampos(i,1)
XLSheet.Cells(lnRowTit,i).VALUE=lcname
XLSheet.Cells(lnRowTit,i).FONT.bold = .T.
XLSheet.Cells(lnRowTit,i).Interior.ColorIndex = 15
XLSheet.Cells(lnRowTit,i).Interior.PATTERN = 1
XLSheet.RANGE(XLSheet.Cells(lnRowTit,i),XLSheet.Cells(lnRowTit,i)).BorderAround(7)
NEXT

XLSheet.RANGE(XLSheet.Cells(lnRowTit,1),XLSheet.Cells(lnRowTit,lnCuantos)).HorizontalAlignment = 3

*************************
*** Cuerpo de la hoja ***
*************************
oConnection = XLSheet.QueryTables.ADD("TEXT;" + cDefault + cCursor + ".txt", ;
XLSheet.RANGE("A" + ALLTRIM(STR(lnRowPos))))

WITH oConnection
.NAME = cCursor
.FieldNames = .T.
.RowNumbers = .F.
.FillAdjacentFormulas = .F.
.PreserveFormatting = .T.
.RefreshOnFileOpen = .F.
.RefreshStyle = 1 && xlInsertDeleteCells
.SavePassword = .F.
.SaveData = .T.
.AdjustColumnWidth = .T.
.RefreshPeriod = 0
.TextFilePromptOnRefresh = .F.
.TextFilePlatform = 850
.TextFileStartRow = 1
.TextFileParseType = 1 && xlDelimited
.TextFileTextQualifier = 1 && xlTextQualifierDoubleQuote
.TextFileConsecutiveDelimiter = .F.
.TextFileTabDelimiter = .F.
.TextFileSemicolonDelimiter = .T.
.TextFileCommaDelimiter = .F.
.TextFileSpaceDelimiter = .F.
.TextFileTrailingMinusNumbers = .T.
.REFRESH
ENDWITH

XLSheet.RANGE(XLSheet.Cells(lnRowTit,1),XLSheet.Cells(XLSheet.ROWS.COUNT,lnCuantos)).FONT.NAME = "Arial"
XLSheet.RANGE(XLSheet.Cells(lnRowTit,1),XLSheet.Cells(XLSheet.ROWS.COUNT,lnCuantos)).FONT.SIZE = 8

XLSheet.COLUMNS.AUTOFIT
XLSheet.Cells(lnRowPos,1).SELECT
oExcel.ActiveWindow.FreezePanes = .T.

WAIT CLEAR

ENDDO

oExcel.Sheets(1).SELECT
oExcel.Cells(lnRowPos,1).SELECT

IF !EMPTY(cFileSave)
oExcel.DisplayAlerts = .F.
oExcel.ActiveWorkbook.SAVEAS(cFileSave)
oExcel.QUIT
ELSE
oExcel.VISIBLE = .T.
ENDIF

GO lnRecno

RELEASE oExcel,XLSheet,oConnection

IF FILE(cDefault + cCursor + ".txt")
DELETE FILE (cDefault + cCursor + ".txt")
ENDIF

RETURN .T.

ENDFUNC

***
***
Avatar
Experto
Como hacer un cursor modificable (2)


*--------------------------------------------------
FUNCTION _Actualizable(tcAlias)
*--------------------------------------------------
* Hace actualizable un cursor
* USO: _Actualizable("MiCursor")
* PARAMETRO:
* tcAlias = Alias del cursor
*--------------------------------------------------
LOCAL lcAliasTmp, lcAliasAnt
lcAliasAnt = ALIAS()
IF EMPTY(tcAlias) OR NOT USED(tcAlias)
WAIT WINDOW NOWAIT " No existe el alias "
RETURN
ENDIF
lcAliasTmp = SYS(2015)
USE DBF(tcAlias) IN 0 SHARE AGAIN ALIAS (lcAliasTmp)
USE DBF(lcAliasTmp) IN (tcAlias) SHARE AGAIN ALIAS (tcAlias)
USE IN (lcAliasTmp)
IF NOT EMPTY(lcAliasAnt)
SELECT (lcAliasAnt)
ENDIF
RETURN
endfunc
Avatar
Experto
Hola que fue te sirvió los archivos que envié


Atentamente.fitocava
Avatar
Experto
Hola si fueras tan amable de cerrar la pregunta muchas gracias
Usuario
Gracias