Edmundo Cáceres Práctica sobre consultas y vistas 2008 Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Consultas Ejercicio 1 Cree una consulta con los campos ART y NOM de la tabla ART, que muestre los nombres de los artículos ordenados alfabéticamente, de menor a mayor. 1. Cree una consulta. Puede hacerlo con ARCHIVO – NUEVO – CONSULTA– NUEVO ARCHIVO. Otra forma es ubicarse en la categoría CONSULTAS de un proyecto, pulsar el botón NUEVO y después el botón NUEVA CONSULTA. Una tercera forma es emitir el comando CREATE QUERY seguido por el nombre que va a tener la nueva consulta. Se abre el DISEÑADOR DE CONSULTAS, en blanco. Dado que suponemos que cuenta con el proyecto FAC, use la segunda forma. Toda consulta trabaja sobre una o más tablas y/o vistas de entrada. Por ello, junto al diseñador se abrirá un diálogo para seleccionar una de estas entradas. Si hay alguna base de datos (BD) abierta, el diálogo será AGREGAR TABLA O VISTA, para elegir lo necesitado. Si no hay una BD abierta, el diálogo será ABRIR, para agregar la primera tabla. Luego se cierra este diálogo, que es reemplazado por AGREGAR TABLA O VISTA, siempre que la tabla abierta sea de BD. Esto se debe a que VFP obtiene de la primera tabla agregada información sobre la BD a que pertenece: esto explica el reemplazo del diálogo, dado que el segundo es más práctico y permite elegir la categoría VISTAS. Este segundo diálogo permanece abierto para seguir agregando tablas o vistas, mediante el botón AGREGAR. Para cerrarlo se usa el botón CERRAR. Este diálogo se puede abrir posteriormente en cualquier momento, eligiendo la opción AGREGAR TABLA del menú contextual sobre el DISEÑADOR DE CONSULTAS. El botón OTRAS de AGREGAR TABLA O VISTA sirve para elegir tablas que no pertenezcan a las BD abiertas, las cuales aparecen en la cuadro combinado BASES DE DATOS. El botón OTRAS presenta el diálogo ABRIR. Estas tablas adicionales pueden ser libres o de otras BD. En el segundo caso, se abrirá la tabla y la BD a que pertenece, agregándose el nombre de ésta a la lista del cuadro combinado. En AGREGAR TABLA O VISTA, bajo el nombre SELECCIONAR hay dos botones: TABLAS y VISTAS. Estos botones cambian lo que muestra el cuadro de lista cuya etiqueta dirá TABLAS EN LA BASE DE DATOS y VISTAS EN LA BASE DE DATOS. 2. Agregue la tabla ART, que se verá como un cursor en el panel superior (entorno) del DISEÑADOR DE CONSULTAS. Cada tabla o vista agregada se representa en el panel superior como cursor. En cada uno se listan verticalmente sus campos, precedidos por un asterisco, que representa todos los campos del cursor. Todos los campos de los cursores agregados aparecen en el cuadro CAMPOS DISPONIBLES de la ficha CAMPOS, prefijados con el nombre del cursor respectivo. 3. En la ficha CAMPOS, transfiera los campos ART.ART y ART.NOM de la lista CAMPOS DISPONIBLES a la lista CAMPOS SELECCIONADOS. Usando CAMPOS DISPONIBLES, la transferencia de un campo se puede hacer seleccionándolo y pulsando el botón AGREGAR, dándole doble click o arrastrándolo a la lista CAMPOS SELECCIONADOS. Usando el cursor, se puede hacer con doble click o arrastrándolo. Para transferir todos los campos de todos los cursores se usa el botón AGREGAR TODOS. Para transferir todos los campos de un solo cursor se usa el asterisco, con doble click o arrastre. Para transferir a la vez algunos campos, se los selecciona en CAMPOS DISPONIBLES o en un cursor y se usa el botón AGREGAR o el arrastre. —1— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 La devolución de un campo de CAMPOS SELECCIONADOS a CAMPOS DISPONIBLES se hace seleccionándolo y pulsando QUITAR, dándole doble click o arrastrándolo. La devolución de todos los campos se hace con el botón QUITAR TODOS. Para devolver algunos campos de un mismo cursor, se los selecciona y se pulsa QUITAR o se los arrastra. Los campos seleccionados son los que la consulta va a producir, contenidos en un cursor que se verá en la ventana EXAMINAR. En este primer ejemplo no veremos que la consulta hace gran cosa, porque lo mismo podríamos lograr examinando la tabla ART. Sin embargo, a medida que avancemos, veremos que tienen mucha potencia. 4. Seleccione la ficha ORDENAR POR y transfiera el campo NOM de CAMPOS SELECCIONADOS a CRITERIOS DE ORDENACIÓN. Los recursos para transferir campos son análogos a los explicados antes. En OPCIONES DE ORDEN active el botón ASCENDENTE. Las consultas permiten ordenar los registros del cursor de salida por uno o varios de sus campos. En este caso, solamente ordenamos por uno sólo, NOM. Note que los campos por los que podemos ordenar son los que componen el cursor de salida, no los de los cursores de entrada: los campos para ordenar son los seleccionados en la ficha CAMPOS. 5. Ejecute la consulta, eligiendo EJECUTAR CONSULTA en el menú contextual o en el menú CONSULTA. Veremos el resultado en una ventana EXAMINAR, de sólo lectura. Compruebe esto tratando de modificar el contenido de cualquier campo: se nos dará el mensaje El control es de sólo lectura. Veremos luego que el resultado de las vistas también es un cursor que se ve en la ventana EXAMINAR, pero que permite modificar el valor de los campos. 6. Salga de la ventana EXAMINAR con ESC. 7. Guarde la consulta con el nombre CON1 y luego ciérrela. Para guardar puede usar ARCHIVO – GUARDAR o ARCHIVO – GUARDAR COMO. Si el archivo aún no está guardado, GUARDAR llamará al diálogo GUARDAR COMO. Si ya está guardado, guardará las nuevas modificaciones. CTRL + S es igual a ARCHIVO – GUARDAR. Cierre el diseñador con ARCHIVO – CERRAR o con ESC. Si pulsa ESC y aún no ha guardado el archivo, VFP preguntará si lo quiere guardar. Si contesta que sí, se presenta el diálogo GUARDAR COMO y después se cierra el diseñador. Otra forma de guardar y salir es con CTRL + W, que pide un nombre para el archivo si todavía no lo tiene. Ejercicio 2 Cree la consulta CON2, similar a CON1, pero que liste solamente los artículos cuyo código de artículo (campo ART), comience con la letra C. 1. Para aprovechar el trabajo realizado en CON1, seleccione este archivo en el proyecto FAC y pulse MODIFICAR. Esto abrirá CON1 en el DISEÑADOR DE CONSULTAS. 2. Dé el comando ARCHIVO – GUARDAR COMO. En el diálogo de igual nombre, denomine CON2 al duplicado a crear. Después de eso, verá que la consulta que queda en el diseñador es CON2, de modo que vamos a trabajar sobre ella. Para saber sobre qué consulta está trabajando, lea la barra de título del diseñador. 3. Seleccione la ficha FILTRO. En NOMBRE DE CAMPO elija ART.ART. En CRITERIOS elija el operador = y en EJEMPLO escriba "C". 4. Guarde la consulta con CTRL + S y luego ejecútela. Salga con ESC de la ventana EXAMINAR y vuelva a dar ESC para salir del diseñador. —2— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 5. La nueva consulta no aparece en el proyecto, porque si bien fue creada y modificada, no fue agregada a él. Para hacerlo, en el ámbito CONSULTAS del proyecto pulse AGREGAR. En el diálogo ABRIR seleccione el archivo CON2 y pulse ACEPTAR. Luego de ello, la nueva consulta quedará registrada en el proyecto y se verá dentro del ámbito CONSULTAS. La ficha FILTROS sirve para hacer que algunos registros de entrada entren al proceso de la consulta y otros no. Para ello se usa un campo, que se compara contra un valor. Si el resultado lógico de la comparación es verdadero, el registro entra al proceso; de lo contrario, el registro se ignora y no influye en el cursor resultante. Que lo establecido en la ficha FILTROS afecta los registros de entrada se pone de manifiesto en la lista NOMBRE DE CAMPO, donde se ofrecen todos los campos de entrada, es decir, los mismos de la lista CAMPOS DISPONIBLES de la ficha CAMPOS o los que se ven en los cursores de entrada. En este ejercicio, el filtro se aplica al campo ART, que también figura en la lista CAMPOS SELECCIONADOS. Pero podríamos haber aplicado el filtro al campo PRE, que no es un campo seleccionado para confeccionar el cursor de salida. La ficha FILTROS permite descartar registros de entrada usando cualquiera de sus campos o expresiones construidas sobre ellos, sin darles salida en el cursor resultante. Este campo o expresión se escribe en NOMBRE DE CAMPO. El filtro establecido en una consulta es estático: permanece fijo mientras no lo modifiquemos en la consulta. Puede darse el caso que usted diseñe la consulta CON2 para que la ejecuten otras personas que no saben nada de diseño. Cuando se quiera que la consulta dé por resultado los registros cuyo código de artículo comience con la letra A, B, D, etc., cualquier otra letra distinta a C, usted, el único experto en este tema, tendrá que modificar CON2. Ahora bien, ¿qué pasará cuando usted no esté presente, porque está enfermo o de vacaciones? Los demás no podrán obtener lo que deseen, hasta que usted no regrese. Este problema no puede solucionarse en las consultas, sino en las vistas, que usan una técnica llamada parametrización, tema que veremos posteriormente. En CRITERIOS aparecen distintos operadores, para comparar si un campo es igual, menor, mayor, etc., que el valor escrito en EJEMPLO. El botón NO sirve para negar el operador elegido, obteniendo no igual (distinto), no menor (mayor o igual), no mayor (menor o igual), etc. El operador =, aplicado a caracteres, considera la igualdad parcial del valor del campo y del ejemplo, de izquierda a derecha, hasta que se acaba el ejemplo. Por ello, en el ejercicio, los valores C01, C02, C03, etc., del campo ART, son iguales al valor del ejemplo, C. El operador = puede aplicarse a campos o expresiones numéricas, de fecha, de fecha–hora y lógicas. El operador == da por iguales los valores del campo y del ejemplo cuando son totalmente iguales, no parcialmente iguales. El operador BETWEEN compara el valor de un campo con un intervalo de valores, que se expresan en EJEMPLO indicando el menor y el mayor, separados por una coma. Así, si en EJEMPLO hubiera escrito A,D, en el resultado vería todos los artículos cuyo código comienzan con A, B, C y D. El operador IN compara el valor de un campo con un conjunto de valores no sucesivos, que se expresan en EJEMPLO listándolos, separados por comas. Si en EJEMPLO hubiera escrito A, C, F, sólo vería los artículos cuyo código comienzan con A, C y F. No hace falta que los valores sean escritos en orden: podría haberlos indicado como A,F,C, como F,A,C o como F,C,A. El operador LIKE sirve para introducir comodines en el valor de EJEMPLO. A diferencia de los conocidos comodines ? y *, SQL usa _ (subrayado) para representar cualquier valor en una posición específica y % (porcentaje) para representar cualquier valor en en una o más posiciones. Por ejemplo, para filtrar los nombres de artículo que comienzan con A, LIKE exige expresar en EJEMPLO —3— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 la expresión A% o "A%". Para filtrar los nombres que tienen una a minúscula en la segunda posición, el filtro se escribe _a% o "_a%". Para filtrar los nombres que tienen dos a minúsculas en cualquier posición, el filtro es %a%a% o "%a%a%". Los ejemplos dados evidencian que LIKE distingue entre mayúsculas y minúsculas. No comentamos el operador IS NULL, porque no nos interesa trabajar con valores nulos. Dado que el campo ART es de caracteres, SQL entiende que sólo se puede comparar contra caracteres, por lo que, si no se escribe entre comillas el valor de EJEMPLO, lo corrige y lo encierra entre comillas. Para evitar problemas, escríbalo siempre entre comillas. El botón M / M sirve para distinguir entre mayúsculas y minúsculas, cuando no se activa. Si no lo activa y escribe c, no se listará ningún artículo que comience con c minúscula. Si lo activa y escribe C o c, listará todos los artículos que comiencen con esa letra. Ejercicio 3 Se quiere una consulta CON3 que muestre los artículos cuyo precio, aumentado un 15%, supere $180. Los campos de salida serán ART, NOM y el nuevo precio. 1. Cree una nueva consulta. Agregue la tabla ART. En la ficha CAMPOS, agregue los campos ART y NOM. . Cree la expresión 2. En FUNCIONES Y EXPRESIONES, llame al GENERADOR DE EXPRESIONES con ART.PRE * 1.15. Cierre el generador. La expresión queda en FUNCIONES Y EXPRESIONES. 3. Pulse el botón AGREGAR. Esto transfiere la expresión a CAMPOS SELECCIONADOS, como un campo calculado. 4. Seleccione la ficha FILTROS. En NOMBRE DE CAMPO seleccione <EXPRESIÓN…>. En el GENERADOR DE EXPRESIONES escriba ART.PRE * 1.15. En CRITERIOS seleccione > y en EJEMPLO escriba 180. 5. Ejecute la consulta. La columna del nuevo precio dice Exp_1 (o Exp_2, o Exp_3, etc., según la cantidad de campos calculados agregados como campo seleccionado). Este título de la columna no es para nada claro, por lo que conviene darle otro más apropiado. 6. En la ficha CAMPOS, seleccione la expresión. Pulse el botón QUITAR, para sacar el campo calculado de CAMPOS SELECCIONADOS y devolverlo a FUNCIONES Y EXPRESIONES. Pulse . En el GENERADOR DE EXPRESIONES, corrija la expresión por ART.PRE * 1.15 AS NUEVO_PRECIO. Cierre el generador. Transfiera la expresión corregida a CAMPOS SELECCIONADOS con el botón AGREGAR. 7. Vuelva a ejecutar la consulta. Ahora la última columna tiene un nombre apropiado. Hemos escrito Nuevo_precio y no Nuevo precio, porque los nombres de campo no aceptan blancos. El guión bajo salva este problema. 8. Guarde la consulta con el nombre CON3. Para evitar perder el trabajo en caso de corte de energía, podría haberla guardado en cualquier paso intermedio, repitiendo la operación cada tanto con con CTRL + S. No olvide guardarla cuando todo esté concluido con éxito. El título de la tercera columna está bien y es completo, pero las otras columnas son ART y NOM, igual al nombre de los campos. Corrijamos estos títulos, para que tengan nombres completos. 9. En la ficha CAMPOS devuelva los campos ART y NOM. En FUNCIONES Y EXPRESIONES escriba ART.ART AS ARTÍCULO y transfiérala a CAMPOS SELECCIONADOS. 10. Haga lo mismo para el campo NOM, escribiendo la expresión ART.NOM AS NOMBRE. 11. En CAMPOS SELECCIONADOS aparecen tres campos calculados, pero no en el orden con que se desea que aparezcan en la ventana EXAMINAR. El que está más arriba será la primera columna, el que —4— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 le sigue será la segunda, y así. Para reordenarlos, mueva la disposición de los campos seleccionados tomándolos de los botones que los preceden y arrastrándolos hacia arriba o abajo. 12. Ejecute la consulta y guárdela cuando esté bien. Ejercicio 4 Se quiere una consulta CON4 que muestre todos los campos de la tabla LINFAC, agregando un campo calculado con el producto del precio por la cantidad. De este modo obtendremos el parcial de cada artículo que compone cada factura. El resultado debe estar ordenado por número de factura y dentro de cada número por el código de artículo. 1. Cree una consulta. Agregue la tabla LINFAC. En la ficha CAMPOS, agregue todos los campos a CAMPOS SELECCIONADOS. 2. En FUNCIONES Y EXPRESIONES escriba LINFAC.PRE * LINFAC.CAN AS PARCIAL y agréguela a CAMPOS SELECCIONADOS. 3. En la ficha ORDENAR POR, agregue el campo FAC a CRITERIOS CENDENTE. Agregue luego el campo ART en orden ASCENDENTE. DE ORDENACIÓN, con orden AS- Si quisiéramos construir un índice por los mismos conceptos para la tabla LINFAC, deberíamos usar la expresión STR(LIFAC.FAC,8,0) + LINFAC.ART e indicar si el orden va a ser ascendente o descentente. El orden se aplica a la totalidad de la expresión, es decir, a cada componente. En las consultas cada componente puede tener su propio orden. Note que, aunque existiera tal índice, SQL no lo tiene en cuenta, por lo que hay que establecer el orden en la ficha ORDENAR POR. 4. Guarde y ejecute la consulta. Ejercicio 5 La consulta CON4 muestra los totales parciales de cada factura, pero no el total general de ellas. Se quiere una consulta, CON5, con el campo FAC y un campo calculado con la suma de los productos parciales entre cantidad y precio, para obtener el total general de cada factura. Los registros de salida deben estar ordenados por factura. 1. Cree una nueva consulta. Agregue la tabla LINFAC. Haga de FAC un campo seleccionado. 2. Agregue como campo seleccionado la expresión SUM(LINFAC.CAN * LINFAC.PRE) AS TOTAL. 3. Guarde y ejecute la consulta CON5. Observe que la ventana EXAMINAR muestra un solo registro. ¿Por qué? La función SUM( ) suma la expresión numérica contenida o calculada en cada registro. Esto lo hace con todos los registros de la tabla LINFAC. Cuando ya no hay más registros a procesar, da por resultado un solo registro, con el total de lo calculado. Por eso se dice que SUM( ) es una función de agrupamiento. Si observa el registro resultante, el campo FAC se refiere a una sola factura, pero el campo TOTAL es el importe de todas las facturas. La información de FAC es incoherente, porque usted eligió este dato para la salida. La incoherencia la genera usted, no SQL. Como SQL debe dar salida a un número de factura, habiendo muchas facturas dará el número de la última que encuentre. Felizmente, dado que usted quiere el total de cada factura, hay una manera de lograrlo. 4. En la ficha AGRUPAR POR, transfiera el campo FAC de CAMPOS DISPONIBLES a CAMPOS AGRUPADOS. 5. Ejecute la consulta. Ahora sí los resultados son los esperados. Observe que CAMPOS DISPONIBLES le ofrece agrupar por cualquier campo de la tabla, esté o no seleccionado como salida. Si usa para agrupar un campo que no va a figurar en la salida, SQL lo —5— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 agregar por su cuenta a CAMPOS SELECCIONADOS de la ficha CAMPOS. Pero si usted quiere agrupar por él pero no tenerlo en la salida, puede eliminarlo de esa lista. Quede claro, entonces, que el agrupamiento afecta los registros de entrada. En el ejemplo, como se quiere un total por cada factura, SQL ordena los registros de entrada de modo que primero queden todos los correspondientes a la factura 1, formando un grupo, luego todos los correspondientes a la factura 2, etc. Teniendo los registros ordenados de esa manera, SQL puede dar un total correcto de la factura 1, que muestra como un único registro en la salida. Lo mismo para la factura 2, etc. Insistamos en cómo trabaja el agrupamiento. Cuando se agrupa, SQL ordena los registros de entrada por el criterio de ordenamiento, formando grupos. Luego, para todos los registros de un grupo de entrada, produce un solo registro de salida con lo calculado. Pone en cero lo calculado y repite el proceso para el grupo siguiente, produciendo otro registro de salida. La dicho en el párrafo anterior se aclara más ejemplificando con datos. Suponga que la tabla LINFAC tiene los siguiente registros, en orden de grabación. Linfac Fac Art Can Pre 1 A05 5 10 2 B01 4 15 3 D03 1 20 1 C02 2 40 2 A05 2 10 1 A04 4 25 3 A02 1 90 3 A06 2 45 2 C01 5 50 Como debe agrupar por FAC, SQL ordena internamente los registros de entrada por tal campo, quedando: Linfac ordenada Fac Art Can Pre 1 A05 5 10 1 C02 2 40 1 A04 4 25 2 B01 4 15 2 A05 2 10 2 C01 5 50 3 D03 1 20 3 A02 1 90 3 A06 2 45 Ahora puede calcular la expresión SUM(LINFAC.PRE * LINFAC.CAN) grupo de la factura 1, el cálculo irá incrementándose como sigue: Linfac ordenada Fac Art Can Pre 1 A05 5 10 1 C02 2 40 1 A04 4 25 AS TOTAL. Comenzando por el Cálculos Linfac.pre * Linfac.can SUM(Linfac.pre * Linfac.can) 50 50 80 130 100 230 —6— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Cuando SQL llega a la factura 2, es porque se ha acabado completamente la factura 1. Entonces genera un registro de salida para la factura 1. Cursor de salida Fac Total 1 230 Con la factura 2 hace lo mismo: Linfac ordenada Fac Art Can Pre 2 B01 4 15 2 A05 2 10 2 C01 5 50 Cálculos Linfac.pre * Linfac.can SUM(Linfac.pre * Linfac.can) 60 60 20 80 250 330 SQL genera un nuevo registro y lo agrega al cursor de salida: Cursor de salida Fac Total 1 230 2 330 Finalmente, con la factura 3, SQL realiza los siguientes cálculos: Linfac ordenada Fac Art Can Pre 3 D03 1 20 3 A02 1 90 3 A06 2 45 Cálculos Linfac.pre * Linfac.can SUM(Linfac.pre * Linfac.can) 20 20 90 110 90 200 SQL agrega el total de la factura 3 al cursor de salida, en un nuevo registro: Cursor de salida Fac Total 1 230 2 330 3 200 Aunque no hemos usado la ficha ORDENAR POR, los registros salen ordenados por factura. Esto es porque SQL, para hacer el cálculo, previamente ordenó internamente los registros de entrada por factura, como se ha indicado. Las entradas, entonces, tienen el orden necesitado para la salida. Si se necesitara otro orden para la salida, por ejemplo por TOTAL descendente, se puede hacer sin ningún inconveniente usando ORDENAR POR, que, como se ha dicho, ordena los registros de salida. Otra advertencia es que el agrupamiento se puede hacer por más de un campo. Por ejemplo, en la tabla ENCFAC podríamos agrupar por los campos CLI y FEC. Cada grupo esaría formado por el valor conjunto de ambos campos, de modo que, a los efectos del cálculo, es lo mismo la combinación CLI – FEC que FEC – CLI. Sin embargo, a los efectos del orden interno, que puede ser aprovechado sin usar la ficha ORDENAR POR, no es lo mismo. Por ello, en CAMPOS AGRUPADOS, cada campo tiene un botón que permite arrastrarlo hacia arriba o abajo, logrando el ordenamiento adecuado: el campo que está arriba es el que tiene mayor prioridad, la cual desciende por los demás campos de modo jerárquico. Ejercicio 6 Se quiere una consulta CON6 que haga básicamente lo mismo que CON5, pero que solamente genere registros de totales para las facturas cuyos importes superen $1000. —7— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 1. Abra CON5 y guárdela como CON6. Cierre CON5. Agregue CON6 al proyecto y ábrala para modificarla. 2. En la ficha AGRUPAR POR pulse el botón CONDICIONES. Esto trae un diálogo de igual nombre, que sirve para filtrar registros de salida. 3. En NOMBRE DEL CAMPO elija el campo calculado TOTAL. En CRITERIOS elija el operador >=. En EJEMPLO escriba 1000. 4. Ejecute y guarde la consulta. El botón CONDICIONES de la ficha AGRUPAR POR sirve para establecer filtros para los registros de salida. Si usted quiere poner filtros a los totales de factura, no puede hacerlo en la ficha FILTROS, porque los filtros establecidos en ella se aplican a los registros de entrada. Como los totales son una suma de los productos precio por cantidad de los registros componentes de cada factura, no existen como datos de la entrada, sino que resultan de cálculos aplicados a cada grupo. Por ello los totales deben filtrarse en los registros de salida, para lo cual existe el diálogo CONDICIONES. Ejercicio 7 Se quiere CON7 que haga lo mismo que CON5, pero que muestre las 10 facturas cuyo totales sean los mayores. 1. Guarde CON5 como CON7. Agregue CON7 al proyecto y entre a modificarla. 2. En la ficha ORDENAR POR, agregue SUM(LINFAC.PRE * LINFAC.CAN) ORDENACIÓN, con opción de orden DESCENDENTE. AS TOTAL a CRITERIOS DE 3. Ejecute la consulta. Aparecen todos los registros, ordenados de mayor a menor por TOTAL. Pero nosotros queremos solamente los 10 primeros registros de esa salida, que tienen los totales mayores. 4. En la ficha VARIOS, desactive el botón TODOS de REGISTROS INCLUIDOS y escriba 10 en NÚMERO DE REGISTROS. 5. Ejecute la consulta y guárdela. Si en lugar de los 10 mejores quisiera el 10% de los registros, deberá activar el botón PORCENTAJE. Ejercicio 8 Cree CON8 para obtener el total vendido de cada artículo. 1. Cree una nueva consulta. Agregue la tabla LINFAC. Seleccione como salida el campo ART y la expresión SUM(LINFAC.PRE * LINFAC.CAN) AS VENDIDO. 2. Agrupe por el campo ART. 3. Ejecute y guarde la consulta. Ejercicio 9 Cree CON9 para obtener todos los campos de la tabla LINFAC, agregando en cada registro el nombre de cada artículo, que debe tomar de la tabla ART. 1. Cree una consulta. Agregue la tabla LINFAC. Agregue todos los campos. 2. En el DISEÑADOR DE CONSULTAS, pulse el botón secundario y elija AGREGAR TABLA. 3. En el diálogo AGREGAR TABLA O VISTA, selecciones la tabla ART y pulse ACEPTAR. Esto abre el diálogo CONDICIÓN DE COMBINACIÓN, en el que se propone una combinación interna entre LINFAC.ART y ART.ART. Pulse ACEPTAR. Cierre el diálogo AGREGAR TABLA O VISTA. —8— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 SQL puede fabricar salidas combinando dos tablas. Combinar es parecido a relacionar las tablas, pero no igual. SQL no maneja relaciones. Las combinaciones consideran situaciones que las relaciones no tienen en cuenta. Para combinar dos tablas, ambas deben tener algo común. En el ejemplo, lo común es el campo ART, que está en ambas tablas. Lo común no es que se llamen igual, sino que tengan datos referidos a lo mismo. Si en una tabla el campo se llamara ART y en la otra se llamara ARTIC, la combinación también podría hacerse, porque ambos contienen códigos de artículo. Al definir la combinación, se indica un campo de una tabla a la izquierda y un campo de otra tabla a la derecha. Esto permite hablar de tabla izquierda y tabla derecha. Fíjese que izquierda y derecha hacen referencia a cómo se definen las tablas en el diálogo CONDICIÓN DE COMBINACIÓN, no a como se ven en el entorno. En este panel, los cursores se pueden arrastrar a cualquier lado, de modo que hablar de tabla izquierda o derecha no tiene sentido, porque el arrastre puede poner la tabla izquierda a la derecha, una tabla bajo la otra, etc. Hay varios tipos de combinaciones. El tipo interna indica que SQL se va a preocupar por fabricar una salida cada vez que un registro de la tabla izquierda coincida con otro de la tabla derecha por el campo ART. Si un registro de la tabla izquierda no tiene un registro coincidente en la tabla derecha, se ignora. Sería el caso de un código de artículo vendido que fuera erróneo, porque no podríamos vender algo que no esté en la lista oficial de los artículos que comercializamos (tabla ART). Simétricamente, si un registro de la tabla derecha no tiene un registro coincidente en la tabla izquierda, también se ignora. Sería el caso de un artículo de la lista oficial que no se hubiera vendido nunca. Sean las tablas LINFAC y ART, con registros hipotéticos. Los registros de una tabla sin coincidencia en la otra aparecen oscurecidos. Fac 1 1 2 2 2 3 3 Linfac Art Can Pre A05 5 10 A04 4 25 A09 4 15 A05 2 10 C01 5 50 A02 1 90 A06 2 45 Art A01 A02 A03 A04 A05 A06 A07 Art Nom Camisa Pantalón Corbata Pañuelo Cinto Zapatos Medias SQL producirá la salida siguiente: Cursor de salida Fac Art Can Pre Nom 1 A05 5 10 Cinto 1 A04 4 25 Pañuelo 2 A05 2 10 Cinto 3 A02 1 90 Pantalón 3 A06 2 45 Zapatos Observe que el registro de ART con código de artículo A05 aparece en las facturas 1 y 2 de LINFAC. Esto significa que el registro de ART se combina con cada uno de los registros de LINFAC, produciendo dos registros en el cursor de salida. Como no hemos ordenado la salida por código de artículo ni por nombre, es confuso. Mejor hubiera sido ordenar por alguno de estos campos. —9— Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 4. Guarde y ejecute la consulta. Ejercicio 10 Cree CON10 para calcular el importe total vendido de cada artículo. La salida debe ordenarse por nombre de artículo. 1. Cree una nueva consulta. 2. Agregue la tabla ART y luego la tabla LINFAC. 3. En el diálogo CONDICIÓN DE COMBINACIÓN, acepte la propuesta de combinar internamente ART.ART con LINFAC.ART. Cierre el diálogo AGREGAR TABLA O VISTA. A los efectos de lograr el propósito de la consulta, en este caso es indistinto cuál tabla estará a la izquierda y cual a la derecha. 4. En la ficha CAMPOS agregue como campos seleccionados ART.ART, ART.NOM y la expresión SUM(LINFAC.CAN * LINFAC.PRE) AS VENDIDO. 5. En agrupar por agregue ART.ART como campo agrupado. 6. En ORDENAR POR agregue ART.NOM como criterio de ordenación. 7. Guarde y ejecute la consulta. Hemos agrupado por código de artículo y hemos ordenado la salida por nombre de artículo. ¿Podríamos haber agrupado por el nombre? En el caso del ejercicio sí, porque todos los nombres son diferentes. Pero en la mayoría de los casos, como clientes, alumnos, socios, etc., es muy común que dos o más clientes, alumnos, etc., tengan códigos distintos, pero se llamen igual. Por ejemplo, sea que los clientes con código 15 y 49 se llamen Juan Carlos González. Si agrupáramos por nombre, daríamos un solo total para Juan Carlos González, lo cual sería un error. Lo correcto sería agrupar por código de cliente, que es el identificador de cada uno y nunca se repite. Si el código de cliente se repitiera, dejaría de ser identificador. Con las tablas del ejemplo anterior, SQL ordenaría las tablas por ART, para poder agrupar: Linfac Fac Art Can Pre 3 A02 1 90 1 A04 4 25 1 A05 5 10 2 A05 2 10 3 A06 2 45 2 A09 4 15 2 C01 5 50 Art A01 A02 A03 A04 A05 A06 A07 Art Nom Camisa Pantalón Corbata Pañuelo Cinto Zapatos Medias Luego produciría la combinación siguiente: Fac 3 1 1 2 3 Combinación Art Can Pre A02 1 90 A04 4 25 A05 5 10 A05 2 10 A06 2 45 Nom Pantalón Pañuelo Cinto Cinto Zapatos Posteriormente agruparía, produciendo lo siguiente, con los campos solicitados: — 10 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Art A02 A04 A05 A06 Nom Vendido Pantalón 90 Pañuelo 100 Cinto 70 Zapatos 90 Finalmente ordenaría por NOM y obtendría el cursor definitivo: Art A05 A02 A04 A06 Nom Vendido Cinto 70 Pantalón 90 Pañuelo 100 Zapatos 90 Ejercicio 11 Cree CON11 para calcular la cantidad de unidades totales vendidas de cada artículo. Ordene la salida por nombre de artículo. 1. La consulta a crear es similar a CON10, de modo que créela a partir de ella y agréguela al proyecto. 2. Lo que varía con respecto a CON10 es que no debe calcular el importe total de ventas por artículo, sino el total de unidades vendidas de cada uno. Elimine el campo seleccionado SUM(LINFAC.CAN * LINFAC.PRE) AS VENDIDO, reemplazándolo por SUM(LINFAC.CAN) AS UNIDADES. 3. Ejecute y guarde la consulta. Ejercicio 12 Cree CON12 para que muestre los campos FAC, FEC, CLI de ENCFAC y el total de cada factura. 1. Cree una nueva consulta. Agregue las tablas ENCFAC y LINFAC, combinándolas internamente por el campo FAC. 2. Agregue como seleccionados los campos FAC, FEC y CLI. Agregue también la expresión SUM(LINFAC.PRE * LINFAC.CAN) AS IMPORTE. 3. Agrupe por ENCFAC.FAC. 4. Guarde y ejecute la consulta. Ejercicio 13 En una nueva consulta CON13, realice lo mismo que en CON12, pero agregando el nombre de cada cliente, que debe tomar de la tabla CLI. 1. Cree CON13 a partir de CON12. Agregue CON12 al proyecto y modifíquela. 2. Agregue la tabla CLI. Acepte en principio la combinación interna ENCFAC.CLI con CLI.CLI. Veremos que esto produce errores, porque cuando hay más de dos tablas en el panel de entorno, se debe observar una regla. 3. Agregue CLI.NOM a campos seleccionados. Reubique los campos, para que el código de cliente salga junto al nombre. 4. Guarde y ejecute la consulta. Aunque el código de cliente varía, siempre aparece el mismo nombre de cliente. Obviamente hay un error, debido a las combinaciones. Active la ficha COMBINACIÓN y verá lo siguiente: — 11 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Tipo Nombre de campo No Criterios Valor Lógico Inner Join Encfac.fac = Linfac.fac Inner Join Encfac.cli = Cli.cli Hay dos líneas, una por combinación. Cada botón abre el diálogo CONDICIÓN DE COMBINACIÓN para la combinación correspondiente, permitiendo modificarla. En TIPO hay una lista desplegable para cada combinación, para elegir su tipo, que se ofrecen en inglés: Inner Join quiere decir combinación interna. En NOMBRE DE CAMPO se define la tabla izquierda y su campo de combinación. En CRITERIOS, en principio, debe definir el operador =, que es el ofrecido inicialmente. En VALOR se define la tabla derecha con su campo. NO niega el criterio, que por lo dicho, en principio no se usa, pues negaría el =, dando distinto. LÓGICO sirve para elegir los operadores AND y OR, permitiendo lograr combinaciones compuestas. Cuando hay varias tablas, la que está a la derecha en una combinación debe estar a la izquierda en la combinación siguiente. Esta regla no se ha observado y es lo que produce el error. El esquema de combinaciones, aplicando la regla, debe ser el siguiente: Tipo Nombre de campo No Criterios Valor Lógico Inner Join Cli.cli = Encfac.cli Inner Join Encfac.fac = Linfac.fac Otra forma de combinar las tablas, también correcta, es: Tipo Nombre de campo No Criterios Valor Lógico Inner Join Linfac.fac = Encfac.fac Inner Join Encfac.cli = Cli.cli Usemos el primer equema. Hay varias formas de corregir el error. Una es seleccionar cada línea de combinación en el panel de entorno, pulsar la tecla SUPRIMIR y trazarla de nuevo, arrastrando del campo de la tabla izquierda al campo de la tabla derecha. Recuerde que izquierda y derecha no se refieren a cómo están dispuestos los cursores en el panel, sino a las tablas de partida y llegada, respectivamente. Para no confundirse, puede mover los cursores para que visualmente queden a la izquierda y derecha, de acuerdo al arrastre. Otra forma es eliminar cada línea en la ficha COMBINACIÓN, ubicándose en ella y pulsando el botón QUITAR. Posteriormente se puede construir cada combinación definiendo su tipo y las tablas y campos izquierdos y derechos. Otra forma es pulsar el botón de cada combinación y tratar de modificarla en el diálogo CONDICIÓN DE COMBINACIÓN. Esto no siempre es posible, porque como la condición ya está definida y se la quiere editar, las posibilidades de tablas izquierdas son todas las que no estén como tabla derecha, porque una tabla no se puede combinar consigo misma. Lo mismo sucede con la tabla derecha. Pero si fuera posible usar este diálogo, quizás resulte que las combinaciones están correctas pero mal ubicadas, infringiendo la regla. Queda todavía el recurso de intercambiarlas, arrastrándolas hacia arriba o hacia abajo con el botón que aparece a la izquierda de cada combinación. Use la primera o segunda formas para corregir el error y lograr el primer esquema. 5. Guarde y ejecute la consulta. Ejercicio 14 Cree Con14 para que muestre el nombre de los clientes y el total comprado por cada uno. Ordene por nombre. 1. Cree una nueva consulta. Agregue las tablas CLI, ENCFAC y LINFAC. Dado que las combinaciones propuestas son correctas, acéptelas. — 12 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 2. Agregue como campo de salida CLI.NOM y SUM(LINFAC.CAN * LINFAC.PRE) AS COMPRADO. 3. Agrupe por CLI.CLI. 4. Ordene por CLI.NOM. 5. Guarde y ejecute la consulta. Ejercicio 15 Cree CON15 para obtener lo comprado por cada cliente en cada factura. Se debe ordenar por nombre de cliente y número de factura. 1. Cree una nueva consulta. Agregue las tablas CLI, ENCFAC y LINFAC. Acepte las combinaciones propuestas, porque son correctas. 2. Agregue como salida CLI.NOM, ENCFAC.FAC y SUM(LINFAC.CAN * LINFAC.PRE) AS COMPRADO. 3. Agrupe por CLI.CLI y ENCFAC.FAC. 4. Ordene por CLI.NOM y ENCFAC.FAC. 5. Guarde y ejecute la consulta. Ejercicio 16 Cree CON16 para obtener el total de ventas en cada provincia. Ordene por nombre de provincia. 1. Cree una nueva consulta. Agregue las tablas PROV, CLI, ENCFAC y LINFAC. Las condiciones de combinación pueden ser como indica cualquiera de los siguientes esquemas: Prov.prv = Cli.prv Linfac.fac = Encfac.fac Cli.cli = Encfac.cli Encfac.cli = Cli.cli Encfac.fac = Linfac.fac Cli.prv = Prov.prv ¿Para qué usar cuatro tablas, si cuando la información a obtener proviene solamente de dos? Porque, para poder llegar de PROV a LINFAC, las tablas con la información necesitada, debemos usar como "puentes" las tablas CLI y ENCFAC. 2. Agregue como salida PROV.NOM y SUM(LINFAC.PRE*LINFAC.CAN) AS VENTAS. 3. Agrupe por PROV.PRV. También podría agrupar por PROV.NOM, porque ningún nombre de provincia se repite. 4. Ordene por PROV.NOM. 5. Ejecute y guarde la consulta. Ejercicio 17 Cree CON17 para que calcule cuántas compras ha hecho cada cliente, sabiendo que cada factura es una compra. Incluya el nombre del cliente y ordene la salida por este concepto. 1. Cree una nueva consulta. Agregue las tablas ENCFAC y CLI, combiándolas por el campo CLI. 2. Agregue como salida el campo CLI.NOM y la expresión COUNT(ENCFAC.FAC) AS FACTURAS. La función COUNT( ) suma 1 por cada factura de cada cliente, obteniendo cuántas son. 3. Agrupe por CLI.CLI o por ENCFAC.CLI. 4. Ordene por CLI.NOM. 5. Guarde y ejecute la consulta. — 13 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Ejercicio 18 Cree CON18 para saber cuánto ha vendido cada vendedor de cada artículo. 1. Cree una nueva consulta. Agregue las tablas VEN, ENCFAC, LINFAC y ART. Las combinaciones pueden ser cualquiera de los dos esquemas siguientes: Ven.ven = Encfac.ven Encfac.fac = Linfac.fac Linfac.art = Art.art Art.art = Linfac.art Linfac.fac = Encfac.fac Encfac.ven = Ven.ven 2. Agregue como campos de salida las expresiones VEN.NOM AS VENDEDOR, ART.NOM AS ARTÍCULO y SUM(LINFAC.CAN*LINFAC.PRE) AS PRODUCCIÓN. 3. Dado que conviene no usar los nombres para agrupar, debe usar los campos VEN y ART. Tiene varias posibilidades: Primer campo (arriba) Ven.ven Ven.ven Encfac.ven Encfac.ven Linfac.art Linfac.art Art.art Art.art Segundo campo (abajo) Linfac.art Art.art Linfac.art Art.art Ven.ven Encfac.ven Ven.ven Encfac.ven Cualquiera de las posibilidades anteriores es válida, porque se producirá un grupo por cada valor diferente de ambos componentes. El orden final de los registros se hará por los nombres de vendedor y de artículo. 4. Ordene por nombre de vendedor y nombre de artículo. 5. Guarde y ejecute la consulta. Ejercicio 19 Se quiere una consulta CON19 que calcule el total de ventas de cada vendedor a cada cliente. Debe dar el nombre del vendedor, el nombre del cliente y el total. El esquema de combinaciones desde un punto de vista lógica sería: Ven.ven = Encfac.ven Encfac.fac = Linfac.fac Encfac.cli = Cli.cli Esquemáticamente, los cursores y combinaciones se verían así (se muestran los nombres de los cursores y de los campos de combinación): Ven Ven Encfac Fac Ven Cli Linfac Fac Cli Cli Este entorno es dificultoso de establecer, porque habría que eliminar las combinaciones y volverlas a trazar por arrastre. Lo que es peor, la consulta no funcionaría, debido a que no se cumple la regla: la tabla derecha de la segunda combinación no es la tabla izquierda de la tercera. El problema se soluciona si ENCFAC se agregar otra vez al entorno. Una tabla se puede agregar varias veces, sin confundir a SQL, porque les da un alias diferente: la primera vez el alias será igual al nombre — 14 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 de la tabla, ENCFAC; pero en adelante el alias será ENCFAC_A, ENCFAC_B, etc. El esquema de combinación correcto, entonces, es: Ven.ven Encfac.fac Linfac.fac Encfac_a.cli = = = = Encfac.ven Linfac.fac Encfac_a.fac Cli.cli Los cursores quedarán como las perlas de un collar, unidos por una cadena de combinaciones: Ven Ven Encfac Ven Fac Linfac Encfac_a Cli Fac Fac Cli Cli La disposición generalizada del dibujo expresa la regla, que llamamos regla de la cadena. La solución indicada funciona en este caso, porque la tercera combinación es 1 – 1: cada valor de factura en los registros de LINFAC tiene un solo registro correspondiente en ENCFAC_A. Si fuera una combinación 1 – N, SQL no la podría manejar adecuadamente y produciría resultados erróneos, por lo que habría que buscar otra solución. 1. Cree una nueva consulta. Agregue las tablas y combinaciones del último esquema. 2. Seleccione como campos las expresiones VEN.NOM LINFAC.PRE * LINFAC.CAN ) AS IMPORTE. AS VENDEDOR, CLI.NOM AS CLIENTE y SUM( 3. Agrupe por VEN.VEN y CLI.CLI o por CLI.CLI y VEN.VEN. 4. Elimine en la ficha CAMPOS los campos seleccionados VEN.VEN y CLI.CLI, para que no aparezcan en el cursor de salida. 5. Ordene por VEN.NOM y CLI.NOM. 6. Guarde la consulta y ejecútela. Ejercicio 20 Se quiere una consulta que calcule el total vendido de cada artículo, por cada vendedor, a cada cliente. Un esquema de combinaciones, lógico pero complicado e ineficaz, sería: Ven.ven Encfac.fac Linfac.fac Art.art Linfac_a.fac Encfac_a.cli = = = = = = Encfac.ven Linfac.fac Art.art Linfac_a.art Encfac_a.fac Cli.cli Este esquema produce resultados erróneos, porque se producen combinaciones 1 – N incorrectas. Veamos dónde está el error. Sea que el artículo A01 se ha vendido en las facturas 15 y 28, como único artículo en cada factura. La factura 15 tiene vendedor 8 y cliente 14. La factura 28 tiene vendedor 55 y cliente 49. Esto queda más claro en el siguiente cuadro: Factura Vendedor Cliente Único 15 8 14 A01 28 55 49 A01 Cuando se procesa la factura 15 del vendedor 8 se producen las siguientes combinaciones: — 15 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Ven Ven 8 8 Encfac Ven Fac 8 15 8 15 Linfac Fac Art 15 A01 15 A01 Art Art A01 A01 Linfac_a Art Fac A01 15 A01 28 Encfac_a Fac Cli 15 14 28 49 Cli Cli 14 49 Al combinar ART con LINFAC_A, SQL combina el artículo A01 de ART con cada aparición de tal código en LINFAC_A, olvidando que debe pertenecer al vendedor 8 y a la factura 15. Esto produce cálculos erróneos, pues se atribuye a la factura 15 el importe de la factura 28. Para solucionar este problema, conviene dividir el problema en dos consultas. La primera, que llamaremos CON20A, producirá una tabla de salida con los campos VEN.NOM, CLI.CLI, ART.NOM y SUM(LINFAC.CAN * LINFAC.PRE) AS IMPORTE. La segunda, que llamaremos CON20B, tendrá como entrada la tabla resultante de CON20A y la tabla CLI, dando como resultado los campos anteriores, pero reemplazanco CLI.CLI con CLI.NOM. Cuando se presentan combinaciones similares a las explicadas, más que analizar las causas de error conviene dividir el problema en dos o más consultas. Veremos más tarde que las vistas son más adecuadas que las consultas para estos casos. Creemos primero la consulta CON20A. 1. Cree una consulta. Agregue las tablas VEN, ENCFAC, LINFAC y ART. Combínelas como indican las tres primeras líneas del esquema anterior, es decir: Ven.ven = Encfac.ven Encfac.fac = Linfac.fac Linfac.fac = Art.art 2. Agregue como salida los campos VEN.NOM SUM(LINFAC.CAN * LINFAC.PRE) AS IMPORTE. AS VENDEDOR, ENCFAC.CLI, ART.NOM AS ARTÍCULO y 3. Agrupe por VEN.VEN, ENCFAC.CLI y ART.ART. 4. Ejecute la consulta para ver los resultados en la ventana EXAMINAR. 5. En el menú CONSULTA, seleccione DESTINO DE LA CONSULTA. 6. En el diálogo DESTINO DE LA CONSULTA pulse el botón TABLA. Aparece el campo NOMBRE DE TABLA. Escriba CON20A y pulse ACEPTAR. 7. Ejecute la consulta para generar la tabla CON20A y guarde la consulta como CON20A. Por defecto, las consultas producen un cursor que se ve en la ventana EXAMINAR. Ese cursor tiene un nombre que calcula SQL a partir del reloj del sistema, de modo que nunca obtiene dos nombres iguales. Los cursores son similares a las tablas en estructura, pero no admiten índices y son destruidos automáticamente cuando se da cualquier comando que cierre las tablas abiertas o cuando se sale de VFP. Tienen extensión TMP, abreviatura de temporal. Puede suceder que el usuario necesite que la consulta no produzca ese cursor, sino que cree un cursor o una tabla con los nombres que él les dé. Las consultas permiten tales salidas, definiendo los destinos CURSOR y TABLA, que solicitan un nombre. Estos cursores o tablas no van a la ventana EXAMINAR, pero quedan abiertos. Al darse un comando para cerrar las tablas, lo cursores, como se ha dicho, desaparecen, pero las tablas quedan en disco. La tabla que produce una ejecución de la consulta es generada nuevamente por otra ejecución, sin que se advierta que ya existe. Creemos finalmente la consulta CON20B. 1. Cree una consulta. Agregue las tablas CON20A y CLI. Combine por el campo CLI. — 16 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 2. Agregue como salida los campos CON20A.VENDEDOR,CLI.NOM CON20A.IMPORTE. AS CLIENTE, CON20A.ARTÍCULO y 3. Ordene por VENDEDOR, CLIENTE y ARTÍCULO. 4. Guarde la consulta como CON20B y ejecútela. Dividir el problema ha simplificado la tarea. Pero trabajar con una tabla generada por una consulta tiene inconvenientes. Primero, para tener una versión actualizada de la tabla CON20A, debemos ejecutar la consulta CON20A antes de ejecutar CON20B. Si olvidamos hacerlo, SQL buscará la tabla existente, lo cual puede dar resultados desactualizados. Segundo, si eliminamos la tabla CON20A para ganar espacio, necesariamente deberemos ejecutar la consulta CON20A antes de CON20B, que usa esa tabla como entrada. Veremos más adelante que estos inconvenientes se evitan con las vistas. Ejercicio 21 Hemos visto que las consultas son muy versátiles para combinar tablas y obtener gran variedad de resultados. Una pregunta que usted puede plantear es si los formularios y los informes pueden aprovechar el producto de las consultas. La respuesta es afirmativa. Para ilustrar someramente esta respuesta vamos a desarrollar algunos ejemplos. Vamos a crear un formulario que contenga un GRID cuyo RECORDSOURCE sea el cursor resultante de una consulta. Los campos del Grid serán los campos del cursor, para lo cual debemos crear primero la consulta. Esos campos serán código de cliente, número de factura y total general de factura. Primero creemos la consulta. 1. Cree una consulta. Agregue las tablas ENCFAC y LINFAC, combinadas por el campo FAC. 2. Agregue como salida ENCFAC.CLI, ENCFAC.FAC y SUM(LINFAC.CAN * LINFAC.PRE) AS IMPORTE. 3. Agrupe por ENCFAC.CLI y ENCFAC.FAC. 4. Ejecute la consulta, para ver el resultado en le ventana EXAMINAR. 5. Elija CURSOR como destino de la consulta y llame CON21 a ese cursor. 6. Guarde la consulta como CON21. 7. Ejecute CON21. Ahora no aparece el resultado en la ventana EXAMINAR. El resultado se ha enviado al cursor CON21, que debe todavía estar abierto. 8. Compruebe que el cursor está abierto: abra la ventana SESIÓN DE DATOS y observe que en el listado ALIAS figura Con21. Seleccione el cursor y pulse CERRAR. Salga de SESIÓN DE DATOS con ESC. Continuemos ahora con el formulario. 9. Cree un formulario. 10. Agregue un GRID. Configure las siguientes propiedades: Objeto Grid Propiedad RecordSourceType RecorSource ColumnCount DeleteMark ScrollBars Width Column1 ControlSource Width — 17 — Valor 3 – Consulta (.QPR) Con21 3 .F. – Falso 2 - Vertical 195 Cli 50 Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Header Caption Column2 ControlSource Width Header Caption Column3 ControlSource Width Header Caption Cliente Fac 50 Factura Importe 60 Importe El valor 3 – CONSULTA (.QPR) de RECORDSOURCETYPE indica que se va a usar como entrada el resultado de una consulta. El nombre de ella se escribe en RECORDSOURCE. El valor CONTROLSOURCE de cada columna es cada campo del cursor CON21 generado por la consulta. Oserve que los campos definidos en CONTROLSOURCE no están prefijados con el alias del cursor. Hemos observado que, colocándoselo, a veces se producen resultados incorrectos. 11. Agregue un botón de comando, con CAPTION y NAME SALIR. 12. Pulse doble click en el botón SALIR y en el evento CLICK de ese objeto escriba: close tables all thisform.release 13. Guarde el formulario con el nombre CON21 y ejecútelo. Hemos introducido el botón SALIR no sólo para que sea más fácil de pulsar que el botón de cierre del formulario, sino para que cierre las tablas y cursores abiertos con el comando CLOSE TABLES ALL. Aunque es innecesario cerrar el cursor CON21, lo hemos hecho para que compruebe, luego de ejecutar el formulario, que ya no aparece en la ventana SESIÓN DE DATOS. Ejercicio 22 El sencillo formulario CON21 es poco práctico, porque el GRID no muestra el nombre de los clientes, sino los códigos. Por otro lado, el GRID muestra todos los códigos de cliente, y no uno en particular que nos interese. Sería preferible un formulario que presente en un LISTBOX, COMBOBOX o GRID los nombres de los clientes y sus códigos, en orden alfabético, tomándolos de la tabla CLI. Elegido un cliente específico, otro GRID, mostraría todas sus facturas, con las fechas e importes. Podríamos usar una consulta para construir un cursor con los campos a mostrar en cada columna de este segundo GRID, más el campo CLI, para filtrar el cliente a mostrar. Creemos primero la consulta. 1. Cree una consulta. Agregue las tablas ENCFAC y LINFAC. 2. Agregue como salida ENCFAC.FAC, ENCFAC.FEC, SUM(LINFAC.CAN * LINFAC.PRE) ENCFAC.CLI. AS IMPORTE y 3. Agrupe por ENCFAC.CLI y ENCFAC.FAC. 4. Ejecute la consulta para controlar los resultados en la ventana EXAMINAR. 5. Envíe el resultado de la consulta al cursor CON22. 6. Guarde la consulta como CON22. Ahora creemos el formulario. 1. Cree un formulario, que se llamará CON22. Agréguele un LISTBOX, un GRID y un botón de comando. 2. En el entorno de datos agregue la tabla CLI. Establezca la propiedad ORDER al índice NOM. 3. Defina las siguientes propiedades: — 18 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Objeto ListBox Propiedad ColumnWidths ColumnCount RowSource RowSourceType Width Grid RecordSource RecordSourceType ColumnCount DeleteMark ScrollBars Width Column1 ControlSource Width Header Caption Column2 ControlSource Width Header Caption Column3 ControlSource InputMask Width Header Caption CommandButton Caption Name Valor 150,0 2 Cli.Nom,Cli 6 - Campos 178 Con22 3 – Consulta (.QPR) 2 .F. - Falso 2 - Vertical 248 Fac 60 Factura Fec 75 Fecha Importe 999,999.99 80 Importe Salir Salir Puede preguntarse por qué no definir las propiedades que subordinarían el GRID a la tabla CLI. El problema radica en que no se puede definir la propiedad CHILDORDER, porque siendo el cursor CON22 de lectura, no se puede crear un índice para él. Debemos, en consecuencia, apelar a un filtro de registros sobre el cursor. Este filtro se aplicará cada vez que se elija un cliente en el LISTBOX, en el evento CLICK de este objeto. 4. En el evento CLICK del LISTBOX, escriba: select con22 set filter to cli=cli.cli go top thisform.grid1.refresh 5. En el evento CLICK del botón SALIR, escriba: close tables all thisform.release 6. Ejecute el formulario. Guárdelo como CON22. Ejercicio 23 Veamos otra forma de realizar lo mismo que hace CON22, pero sin definir el entorno de datos y usando comandos para crear el cursor CON23 y abrir la tabla CLI. 1. Cree el formulario CON23 a partir del formulario CON22. 2. Abra el entorno de datos y elimine el cursor de la tabla CLI. 3. En el GRID, cambie el valor de la propiedad RECORDSOURCETYPE por 1 – ALIAS y el de la propiedad RECORDSOURCE por CON23. — 19 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 4. En el evento LOAD del formulario, escriba: close tables all use cli in 0 order nom noupdate En el menú VENTANA elija la ventana ADMINISTRADOR DE PROYECTOS – FAC. Seleccione la consulta CON22 y pulse el botón MODIFICAR. En el DISEÑADOR DE CONSULTAS pulse el botón secundario y elija VER SQL. Se abre la ventana CON22.QPR [SÓLO LECTURA], donde aparece el comando SELECT producido por lo definido en el diseñador. Seleccione todo el texto y cópielo. Cierre la ventana y el diseñador con ESC. Vuelva a la ventana CÓDIGO del evento LOAD del formulario. Al final del texto pegue el comando Select de SQL. Corrija la última línea, reemplazando CON22 por CON23. El texto definitivo debe quedar como sigue: close tables all use cli in 0 order nom noupdate SELECT Encfac.fac, Encfac.fec, SUM(Linfac.can*Linfac.pre) AS importe,; Encfac.cli; FROM fac!encfac INNER JOIN fac!linfac ; ON Encfac.fac = Linfac.fac; GROUP BY Encfac.cli, Encfac.fac; INTO CURSOR con23 5. En el evento CLICK del LISTBOX, modifique la primera línea, cambiando CON22 por CON23. 6. Ejecute el formulario. Hemos creado la consulta CON23 sin necesidad de usar el diseñador correspondiente. Esto se debe a que el diseñador de consultas produce en definitiva un comando SELECT de SQL, que es lo esencial. El diseñador es un recurso intermedio que facilita la construcción de SELECT, pero SELECT se puede escribir directamente. En este ejemplo, hemos copiado el SELECT correcto de la consulta CON22, lo hemos pegado donde nos hace falta y lo hemos corregido ligeramente. Ejercicio 24 El formulario CON23 muestra los importes comprados en cada factura del cliente elegido en el LISTBOX, pero no el total general de esos importes. Este podría aparecer al pie del GRID, en un TEXTBOX. Para calcularlo, podríamos duplicar el comando SELECT, con leves modificaciones. El primer SELECT sería igual al original, cambiando el nombre del cursor a CON24A. El segundo SELECT produciría el cursor CON24B, que debería agrupar solamente por cliente. 1. Cree CON24 a partir de CON23. 2. Corriga la propiedad RECORDSOURCE de GRID1 por CON24A. 3. Entre a la ventana CÓDIGO del evento LOAD del formulario, seleccione todo el comando SELECT, cópielo y péguelo al final. Corrija las líneas que se ven en negrita en el texto definitivo siguiente: close tables all use cli in 0 order nom noupdate SELECT Encfac.fac, Encfac.fec, SUM(Linfac.pre*Linfac.can) AS importe,; Encfac.cli; FROM fac!encfac INNER JOIN fac!linfac ; ON Encfac.fac = Linfac.fac; GROUP BY Encfac.cli, Encfac.fac; INTO CURSOR con24a SELECT Encfac.cli, SUM(Linfac.pre*Linfac.can) AS general; FROM fac!encfac INNER JOIN fac!linfac ; ON Encfac.fac = Linfac.fac; GROUP BY Encfac.cli; INTO CURSOR con24b 4. Agregue un LABEL y un TEXTBOX al pie del GRID. Modifique las siguiente propiedades: — 20 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Objeto Label Propiedad Caption AutoSize InputMask Width TextBox ControlSource Name Valor Total general .T. – Verdadero 999,999,999.99 100 con24b.general general 5. Modifique el evento CLICK del LISTBOX, para que quede como sigue: select con24a set filter to cli=cli.cli go top thisform.grid1.refresh select con24b set filter to cli=cli.cli go top thisform.general.refresh 6. Ejecute el formulario. Vistas Ejercicio 1 Cree la vista VIS1 para que produzca un cursor con solamente los artículos cuyo código de artículo (campo ART) se indique al momento de la ejecución. Este ejercicio es similar al Ejercicio 2 de Consultas. Cada vez que se examina, CON2 da salida a los artículos cuyo nombre comienza con C. Lo mismo se puede hacer en las vistas, pero para darles mayor flexibilidad se las puede construir con parámetros. Los parámetros son cualquier nombre válido precedido por un signo ? que se usan para construir filtros sobre los registros de entrada y de salida. Se colocan en la columna EJEMPLO de la ficha FILTRO y del diálogo CONDICIONES. Cada vez que se examina una vista que posee parámetros, antes de comenzar a trabajar, SQL pide un valor específico para cada parámetro. 1. Ubíquese en la categoría VISTAS LOCALES y pulse el botón NUEVO. Esto abre el DISEÑADOR VISTAS, que es muy parecido al diseñador de consultas, aunque hay algunas diferencias. DE 2. Agregue la tabla ART. En la ficha CAMPOS agregue los campos ART.ART y ART.NOM. 3. Seleccione la ficha FILTRO. En NOMBRE DE CAMPO elija ART.ART. En CRITERIOS elija el operador = y en EJEMPLO escriba ?INICIAL. 4. Guarde la consulta con CTRL + S, llamándola VIS1. 5. Examínela con EJECUTAR CONSULTA del menú secundario. Aparece el diálogo PARÁMETRO DE VISTA, con el texto Escriba un valor para Inicial. En el campo en blanco escriba "C". Pulse ACEPTAR. Ahora se abre la ventana EXAMINAR, con los registros cuyo nombre comienza con C. Salga con ESC. 6. Vuelva a examinar la vista, pero ahora escriba el valor A para el parámetro. El proceso se repite, pero los registros mostrados comienzan ahora con A. 7. Salga del diseñador. VIS1 aparece registrada en la categoría VISTAS LOCALES. A diferencia de las consultas, las vistas no se guardan en archivos por separado, sino en la base de datos actual. Las consultas pueden agregarse a un proyecto. También pueden quitarse de él, — 21 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 permaneciendo como archivos independientes. Las vistas no pueden agregarse a una base de datos, sino crearse en ellas; si se quitan, se eliminan definitivamente. Las vistas tienen como destino único un cursor que se ve en la ventana EXAMINAR. SQL crea el nombre de este cursor desde el reloj de la computadora. A diferencia de las consultas, el cursor es de lectura y escritura, es decir, permite modificar campos, agregar nuevos registros o marcarlos para destruir. Para probar esta propiedad, examine la vista otra vez. De lo dicho en el párrafo anterior, surge inmediatamente la pregunta sobre el sentido de las altas, bajas y cambios en un cursor que va a desaparecer al dar un comando que cierre tablas. La respuesta es que existe la posibilidad de mandar a las tablas de entrada las modificaciones hechas en el cursor. Veremos este tema más adelante. Al reconocer que INICIAL es un parámetro, porque va precedido por un signo de pregunta, SQL pide el valor que le queremos dar en el diálogo PARÁMETRO DE VISTA. Para que nos indique cuál es el tipo de datos del parámetro, debemos hacer lo que dice el punto siguiente. 8. Para indicar el tipo de datos del parámetro, emita el comando CONSULTA – PARÁMETROS DE VISTA. Esto abre el diálogo de igual nombre. En la columna NOMBRE escriba INICIAL. En la columna TIPO seleccione CARÁCTER. 9. Examine la vista. Ahora el diálogo PARÁMETRO DE VISTA es más específico, pues dice Escriba un valor de tipo carácter para Inicial. Esta especificación es más útil, porque nos orienta sobre si debemos introducir números, caracteres, fechas, etc. Cuando una vista usa muchos parámetros, habrá uno de estos diálogos para cada uno, donde la aclaración del tipo de datos facilita la tarea. 10. Guarde los cambios. Note que, al estar activo el diseñador de vistas, no aparece ningún menú VISTA, sino el ya conocido CONSULTA. Del mismo modo, para producir la vista, no hay una opción EJECUTAR VISTA, sino la ya conocida EJECUTAR CONSULTA. Ejercicio 2 Cree la vista VIS2 para que muestre las facturas de un vendedor y un cliente parametrizados. Trabaje solamente con la tabla ENCFAC. Ordene la salida por factura. 1. Cree una vista. Agregue la tabla ENCFAC y todos sus campos. 2. En la ficha FILTRO, escriba los filtros siguientes: Encfac.ven Encfac.cli = ?Vendedor = ?Cliente 3. En CONSULTA – PARÁMETROS DE VISTA especifique que VENDEDOR y CLIENTE son numéricos. 4. En ORDENAR POR seleccione el campo ENCFAC.FAC. 5. Guarde y examine la vista. Aparecen dos diálogos PARÁMETRO DE VISTA, uno por parámetro. 6. En el diseñador, con el botón secundario pulse VER SQL. Aunque usted no lo ha definido, el operador que une ambos filtros es AND, por ser el operador por defecto. Ello se ve en la cláusula WHERE del comando SELECT, donde dice: Ejercicio 3 WHERE Encfac.cli = ?Cliente; AND Encfac.ven = ?Vendedor Cree la vista VIS3, similar a VIS2, pero que agregue el importe total vendido por el vendedor al cliente. Trabaje solamente con las tablas ENCFAC y LINFAC. Ordene la salida por factura. — 22 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 1. Cree VIS2 a partir de VIS1. 2. Agregue la tabla LINFAC, combinándola con ENCFAC por el campo FAC. 3. Agregue SUM(LINFAC.CAN * LINFAC.PRE) AS TOTAL como campo de salida. 4. Guarde y examine la vista. Note que no ha hecho falta agrupar por vendedor y cliente, porque los filtros han reducido el universo de registros a los de un solo vendedor y un solo cliente. Ejercicio 4 Cree la vista VIS4 que muestre los campos ART, NOM y PRE de la tabla ART y permita actualizar indirectamente el campo PRE de tal tabla. Con indirectamente queremos decir que, si cambiamos el campo PRE del cursor de salida, ese cambio modifique el valor PRE de la tabla ART. ¿En qué registro de la tabla ART se producirá ese cambio indirecto? Pues exactamente en el registro que origina el registro que modificamos en el cursor de salida. Primero, vamos a corregir el campo PRE de la tabla ART, exigiendo mediante la regla de validación que no pueda ser nulo ni negativo. Si esto sucede, queremos que VFP dé el mensaje "Precio debe contener un valor positivo". Esta modificación la introducimos para explicar una característica de las vistas. 1. En el ADMINISTRADOR DE PROYECTOS elija la tabla ART y pulse el botón MODIFICAR. 2. En la ficha CAMPOS del DISEÑADOR DE TABLAS elija el campo PRE. 3. En REGLA de validación escriba la expresión PRE > 0. 4. En MENSAJE de validación escriba "PRECIO DEBE CONTENER UN VALOR POSITIVO". 5. Pulse ACEPTAR. 6. Examine la tabla ART. Ubíquese en algún campo PRE y escriba 0. Al tratar de salir del campo, aparecerá el mensaje de error. Pulse el botón VOLVER, para reponer el valor anterior. Este experimento ha servido para ver cómo funciona una regla de validación de campo. Ahora cree la vista VIS4. 1. Agregue la tabla ART al panel de entorno. 2. Agregue todos los campos a CAMPOS SELECCIONADOS. 3. Seleccione PRE en CAMPOS SELECCIONADOS y pulse el botón PROPIEDADES. Esto abre el diálogo PROPIEDADES DEL CAMPO DE LA VISTA. Dado que queremos que el campo PRE pueda ser modificado en el cursor de salida, mandando el nuevo valor a la tabla ART, podría suceder que en el cursor reemplacemos un precio por un valor nulo o negativo. Pero el cursor funcionaría incorrectamente si aceptara esto, ya que estaría en desacuerdo con la tabla. Lo correcto sería que el cursor tuviera una regla y un mensaje de validación del campo PRE, similares a los que tiene el campo PRE de la tabla ART. Para eso, precisamente, sirve el diálogo PROPIEDADES DEL CAMPO DE LA VISTA. Funcionalmente es exactamente igual a las posibilidades que se ven en la ficha CAMPOS de una tabla base, debajo de las definiciones de campos, tipos, anchos, etc. En el DISEÑADOR DE TABLAS elegimos el campo en la columna NOMBRE. Como en el diálogo PROPIEDADES DEL CAMPO DE LA VISTA no aparece esa columna, la forma de elegirlo es abriendo la lista desplegable CAMPO y seleccionando el deseado. 4. Abra la lista CAMPO y elija ART.PRE. 5. En REGLA escriba PRE > 0. 6. En MENSAJE escriba "PRECIO DEBE CONTENER UN VALOR POSITIVO". — 23 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Ahora entenderá para qué modificamos inicialmente la tabla ART, introduciendo una regla y un mensaje de validación para el campo PRE. No sería congruente que, en la tabla, el campo PRE estuviera sujeto a una regla de validación y una vista permitiera modificar indirectamente su contenido sin observar tal regla. Como los cursores de salida permiten modificar cualquier campo, nos queda definir que sólo las modificaciones del campo PRE del cursor se envíen al campo PRE de la tabla ART. 7. Seleccione la ficha CRITERIOS DE ACTUALIZACIÓN del DISEÑADOR DE VISTAS. En la lista desplegable TABLA aparece ART. Esta lista muestra las tablas del panel de entorno. En este ejercicio, sólo trabajamos con la tabla ART, por lo que no aparece ninguna otra. El cuadro central está dividido en tres columnas, una encabezada por un ícono , otra por un íco- no y la última llamada NOMBRE DEL CAMPO. En esta última columna se ven los campos del cursor, uno por línea. La columna Llave muestra una tilde en la línea de ART. Esto indica que este campo se va a usar como clave para buscar en la tabla de entrada ART el registro cuyo campo PRE debe ser modificado con el valor modificado en el campo PRE del cursor. Que sea clave quiere decir que identifique el registro a modificar de modo inequívoco. El campo ART es precisamente el campo clave de la tabla ART, que nos ha permitido construir el índice principal de esa tabla. Nótese que, sin hacer nosotros nada, este campo apareció con tilde en la columna Llave. Esto se debe a que hay un índice principal por él. Si en lugar de principal fuera un índice candidato, VFP no supone que es clave. Esta es una diferencia de funcionamiento entre índices principales e índices candidatos. La columna Lápiz muestra una tilde en la línea de NOM y otra en la línea de PRE. Esto indica que las modificaciones en los valos de estos campos se van a enviar a la tabla. En principio, SQL supone que todos los campos, excepto los campos clave, van a ser de este tipo. En nuestro caso, como sólo queremos que esto suceda con el campo PRE, deberemos destildar el campo NOM. Nótese que la línea de ART no tiene tilde en la columna Lápiz. Esto se debe a una actitud prudente de SQL. Aunque los cambios de clave se pueden enviar a la tabla, esto puede traer varios problemas que necesitan ser tratados adecuadamente. Como es un tema complejo, nos limitamos a recomendar seguir con la prudencia de SQL, es decir, nunca hacer actualizables los campos clave. Si por equivocación destildamos campos clave y no recordamos cuáles son, podemos recurrir al botón RESTABLECER CLAVES, que vuelve a marcarlos, teniendo en cuenta que forman la expresión de índices principales. Si destildamos campos actualizables y queremos volver a marcarlos todos, el botón ACTUALIZAR TODOS realiza esta tarea. El hecho de marcar algunos o todos los campos como actualizables no los hace inmediatamente tales, sino que es necesario poner en vigencia esta modalidad. Para ello se usa la casilla de verificación ENVIAR ACTUALIZACIONES (SQL). La porción derecha de la ficha CRITERIOS DE ACTUALIZACIÓN, que incluye los rubros LA CLÁUSULA SQL WHERE INCLUYE y ACTUALIZAR USANDO no nos interesan, por referirse principalmente a vistas remotas. 8. Controle que tenga tilde la columna Llave en el campo ART y la columna LÁPIZ solamente en el campo PRE. 9. Active la casilla ENVIAR ACTUALIZACIONES (SQL). — 24 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 10. Guarde y examine la vista. Tome nota de algunos códigos de artículo y modifique el precio. Cierre la vista. Examine la tabla ART y compruebe que los precios que modificó en el cursor de salida han cambiado también en la tabla. Si quiere comprobar el efecto de ENVIAR ACTUALIZACIONES (SQL), modifique la vista VIS4 desactivando esta casilla. Si examina nuevamente la vista y cambia otros precios, cuando salga de ella y examine la tabla, verá que tales cambios no la han modificado. Ejercicio 5 Veamos cómo realizar una vista que realice lo mismo que la consulta del Ejercicio 20. Éste calcula el total vendido de cada artículo, por cada vendedor, a cada cliente. Para lograr este propósito, diseñamos dos consultas, CON20A y CON20B, que creaban una tabla "inevitable", CON20A. Trabajando con vistas esa tabla es innecesaria. Por otro lado sería imposible de crearla, porque las vistas tienen como único destino un cursor de nombre no controlable que se ve en la ventana EXAMINAR. Cree primero la vista VIS5A. 1. Agregue las tablas VEN, ENCFAC, LINFAC y ART. Combínelas como indica este esquema: Ven.ven = Encfac.ven Encfac.fac = Linfac.fac Linfac.fac = Art.art 2. Agregue como salida los campos VEN.NOM SUM(LINFAC.CAN * LINFAC.PRE) AS IMPORTE. AS VENDEDOR, CLI.CLI, ART.NOM AS ARTÍCULO y 3. Agrupe por VEN.VEN, ENCFAC.CLI y ART.ART. Elimine estos campos de CAMPOS SELECCIONADOS de la ficha CAMPOS. 4. Examine la vista para ver los resultados en la ventana EXAMINAR. Cree ahora cree la vista VIS5B. 1. Agregue la vista VIS5A y la tabla CLI. Combine por el campo CLI. 2. Agregue como salida los campos VIS5A.VENDEDOR,CLI.NOM VIS5A.IMPORTE. AS CLIENTE, VIS5A.ARTÍCULO y 3. Ordene por VENDEDOR, CLIENTE y ARTÍCULO. 4. Examine la vista. Cuando una vista 2 incluye en el panel de entorno otra vista 1, SQL debe ejecutar la vista 1 previamente a ejecutar la vista 2, puesto que una de sus entradas es precisamente el cursor resultante de la vista 1. Esta inclusión de una vista dentro de otra puede repetirse varias veces. La inclusión de vistas permite ir obteniendo cursores de salida que quedan abiertos (recuerde que se eliminan si se emite un comando para cerrar las tablas abiertas, comandos que en la ejecución sucesiva no se utilizan). Si una vista 1 produce un cursor 1, éste queda abierto y puede ser tomado como entrada para una vista 2; si ésta produce como salida un cursor 2, puede tomarse como entrada para una vista 3, y así sucesivamente. Técnicamente, una vista es un comando Select de SQL. En el caso de una vista que incluye otra vista, es en realidad un comando Select que incluye otro comando Select. El empleo inmediato de un cursor generado por una vista como entrada de otra vista evita generar tablas y preocuparse por eliminarlas. — 25 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 Ejercicio 6 Creemos un formulario similar a una factura impresa en papel. Queremos elegir en un COMBOBOX la factura a desplegar. Cuando se haga esto, se verá la fecha, el nombre del cliente y el total de la factura en respectivos TEXTBOXES. El detalle de cada artículo vendido, incluyendo código, nombre, cantidad, precio e importe parcial, se verán en un GRID. Las opciones del ComboBox se construirán a partir de una vista, que contendrá los campos factura, fecha, cliente e importe total de la factura. El aspecto del formulario será como el siguiente: Creemos la vista VIS6 con los campos indicados. Esta vista no puede ser la hija de una relación temporal , porque necesitaría un índice que no sabemos generar. Pero sí puede ser la madre de una relación temporal, porque una relación temporal necesita uno o más campos de la tabla madre y un índice en la tabla hija. Las tablas hijas van a ser CLI, para obtener el nombre del cliente, y LINFAC, para obtener las líneas componentes de la factura. Cuando elijamos una factura en el COMBOBOX, podremos "refrescar" directamente los campos fecha e importe total, porque serán parte del mismo registro del cursor producido por la vista, e indirectamente el nombre del cliente y el GRID, por relaciones temporales con las tablas CLI y LINFAC. Notemos que, para obtener la descripción de los artículos, deberemos trazar una relación temporal de LINFAC a ART, relación que se materializará en cada registro del Grid y que no interviene en la subordinación de CLI y LINFAC a VIS6. 1. Cree la nueva vista agregando las tablas ENCFAC y LINFAC al panel de entorno, combinándolas por el campo común FAC. 2. Seleccione los campos FAC, FEC, CLI y SUM(LINFAC.CAN * LINFAC.PRE) AS IMPTOT. — 26 — Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 3. Agrupe por ENCFAC.FAC (o por LINFAC.FAC). 4. Guarde la vista como Vis6 y ejecútela para controlar que todo va bien. Cree ahora el formulario. 1. Agregue los objetos que muestra el gráfico anterior. 2. Defina las siguientes propiedades: Objeto Form1 Label1 ComboBox Label2 TextBox1 Label3 TextBox2 Grid1 Column1 Header1 Column2 Header1 Column3 Header1 Column4 Header1 Column5 Label4 Propiedad Caption Caption AutoSize RowSource RowSourceType ColumnCount ColumnWidths Caption AutoSize ControlSource Name Caption AutoSize ControlSource Name Width RecordSource ColumnCount DeleteMark ScrollBars Name ControlSource Width Alignment Caption ControlSource Width Alignment Caption ControlSource Width Alignment Caption ControlSource Alignment Caption ControlSource Alignment Caption AutoSize Caption — 27 — Valor Despliegue de facturas Factura .T. – Verdadero Vis6.Fac 6 – Campos 1 75 Fecha .T. – Verdadero Vis6.Fec Fecha Cliente .T. – Verdadero Cli.Nom Cliente 200 Linfac 5 .F. 2- Vertical Linfac Linfac.Art 30 2 – Medio centro Art Art.Nom 200 2 – Medio centro Descripción Linfac.Can 60 2 – Medio centro Cantidad Linfac.Pre 2 – Medio centro Precio linfac.can*linfac.pre 2 – Medio centro Importe .T. – Verdadero Total Edmundo A. Cáceres — Práctica sobre consultas y Vistas — 2008 TextBox3 ControlSource InputMask Name CommandButton1 Autosize Caption Name Vis6.Imptot 999,999.99 Imptot .T. – Verdadero Salir Salir 3. En el entorno de datos agregue la vista Vis6 y las tablas Cli, Linfac y Art. 4. Trace las siguientes relaciones: Tabla madre Vis6 Vis6 Linfac Campo Fac Cli Art Tabla hija Linfac Cli Art 5. En el evento CLICK del COMBOBOX, escriba: thisform.fecha.refresh thisform.cliente.refresh thisform.imptot.refresh 6. En el evento Click del CommandButton, escriba: thisform.release 7. Guarde el formulario como Vis6 y ejecútelo. — 28 — Índice Fac Cli Art