Bases de datos con Delphi

Anuncio
Bases de datos con Delphi
1. Introducción
Cuando queramos desarrollar una aplicación con Delphi que dé acceso a una base de datos, no
debemos perder nunca este doble punto de vista: la aplicación será, por una parte, cliente de un
servidor de base de datos y, por otra parte, será el interface de usuario de la base de datos,
para todas las tablas o sólo para algunas (eso ya depende de la amplitud de la aplicación con
respecto al total de los datos). Debemos centrarnos en un buen diseño de la aplicación, pues
esto facilita al usuario la edición de datos, y a nosotros, como programadores, el mantenimiento,
sea como sea de complejo el modelo de datos sobre el que trabajemos.
Para ello, debemos conocer muy bien tanto el modelo de datos de la base de datos, como la
filosofía de trabajo con bases de datos en Delphi. En este curso vamos a preocuparnos,
lógicamente, de la filosofía de trabajo con Delphi.
Delphi utiliza un intermediario para conectar con la base de datos: se llama BDE (Borland
Database Engine). Puede conectar con diversos tipos de bases de datos de forma directa
(Interbase, Paradox, Informix, ...) o bien a través de ODBC. Así pues, es el BDE el que realiza el
trabajo duro de "hablar" con el servidor de base de datos, quedándonos a nosotros una tarea
mucho más sencilla: poder olvidarnos de cómo es la estructura interna (a nivel de estructura de
ficheros) de la base de datos, centrándonos en las tablas como idea y en el diseño de las
consultas.
Hay un concepto clave para todo esto: el concepto de alias. Se trata de un nombre lógico (que
no tiene por qué coincidir con el nombre del fichero físico de la base de datos) con el que Delphi
reconocerá a la base de datos. Así, creamos un alias para la base de datos, y desde Delphi no
tendremos que preocuparnos de la ruta. Especificaremos estos datos previamente accediendo
directamente al BDE Administrator desde el panel de control, o bien usando la utilidad SQL
Explorer. En los anexos se detalla cómo hacerlo.
Delphi separa en dos grupos los componentes de bases de datos: los componentes de acceso a
datos (que se encuentran en la pestaña Data Access) y los componentes visuales que muestran
datos (en la pestaña Data Controls).
La filosofía es separar el contenido de la forma. Así, en los componentes visuales
especificaremos cómo queremos que el usuario vea los datos, y en los componentes de acceso a
datos programaremos cómo obtener los datos que necesitamos. Hay un componente muy
específico que enlazará nuestro acceso a datos con nuestra visualización de datos, y que es el
que se encargará de proveer al control visual de los datos que genera el control no visual de
acceso a datos.
2.i. Descripción rápida de Data access
Comenzamos dando una primera mirada a los componentes de la paleta Data access que
trataremos en este curso. Todos estos componentes son no visuales y permiten que los datos
lleguen a la aplicación.
Paleta DATA ACCESS
TDatabase
Encapsula una conexión cliente/servidor a una única base de datos. A pesar de que si no
incluimos un componente de este tipo, Delphi usa uno de forma temporal, será
conveniente empezar dando a nuestra aplicación uno o más componentes de este tipo
para poder añadir algunos parámetros adicionales.
TTable
Representa un conjunto de datos que recupera todas las columnas y registros de una
tabla de la base de datos. Tiene propiedades y métodos que nos permiten movernos por
el conjunto de datos y encontrar datos que cumplan un determinado patrón de
búsqueda.
TQuery
Representa un conjunto de datos que recupera un subconjunto de columnas y registros
de una o más tablas de bases de datos basadas en una consulta SQL. Al igual que
TTable, tiene propiedades y métodos que nos permiten movernos entre los datos y
escoger aquellos que cumplan ciertas características requeridas por la aplicación.
TStoredProc
Representa un conjunto de datos que recupera uno o más registros de una tabla de base
de datos basándose en un procedimiento almacenado definido para un servidor de base
de datos. Sólo tiene sentido usarlo cuando la base de datos soporta esta característica.
TDataSource
Actúa como un conducto entre otros componentes de acceso a datos y controles visuales
de datos. Es el encargado de que los datos de componentes como TTable, TQuery y
TStoredProc puedan mostrarse de forma cómoda para el usuario en los controles
visuales de datos.
La paleta Data access tiene algunos componentes más, pero con los que describiremos en este
curso, hay más que suficiente para hacer aplicaciones medianas-grandes.
2.ii. Descripción rápida de Data controls
Ahora le toca el turno a los componentes de visualización de datos:
Paleta DATA CONTROLS
TDBGrid
Muestra y edita registros de conjunto de datos en formato de tabla. Puede ser la tabla
completa o sólo algunas de las columnas.
TDBNavigator
Mueve el cursor a través de registros de un conjunto de datos, permite editar e insertar
registros, almacena los registros modificados o nuevos, cancela el modo de edición y
actualiza la visualización de datos. Permite una cómoda navegación por conjuntos
grandes de registros.
TDBText
Muestra un campo como si fuera una etiqueta.
TDBEdit
Muestra y edita un campo en un cuadro de edición.
TDBListBox
Muestra una lista con opciones para introducir un campo.
TDBComboBox
Muestra un cuadro de edición y una lista desplegable de elecciones para editar y entrar
en un campo.
TDBCheckBox
Muestra y configura una condición de campo booleana en un cuadro de comprobación.
TDBRadioGroup
Muestra y configura opciones únicas para un campo de un grupo de botones de radio.
TDBLookupListBox
Muestra una lista con opciones derivadas de un campo en otro conjunto de datos para
entrar en un campo.
TDBLookupComboBox
Muestra un ComboBox de opciones derivada de un campo de otro conjunto de datos
para introducirlos en un campo
3. Módulos de datos
Antes de comenzar a detallar los componentes que usaremos, vamos a hablar de esta peculiar
característica de Delphi.
Un módulo de datos es una clase especial de Delphi que se usa para la gestión centralizada de
componentes no visuales de una aplicación. Generalmente incluye componentes para el acceso a
datos (como TDatabase, TTable, TQuery, ...), pero también puede incluir otros componentes no
visuales (como TTimer, TOpenDialog, TImageList, etc). Un módulo de datos nos permite:
•
•
•
Mantener todos los componentes de acceso a datos en un solo contenedor visual en
modo de diseño, en lugar de duplicarlos para cada form de la aplicación
Diseñar tablas y consultas una sola vez y usarlas en varios forms, en lugar de crearlas
por separado para cada form.
Guardarlo en el Object Repository para poder reutilizarlo.
La centralización de recursos para la aplicación quizá sea una de las características más
interesantes. Por ejemplo, un cuadro de diálogo de apertura de ficheros es un recurso candidato
a ser centralizado. Si tenemos una aplicación con 10 forms que necesiten de un cuadro de
diálogo, tenemos dos opciones, crear 10 componentes, uno para cada form, o crear un único
componente de cuadro de diálogo y usarlo en los 10 forms.
El método de trabajo que usaremos será el de crear los componentes no visuales en un módulo
de datos, y usarlo en todas las units que lo requieran. Así lo tendremos disponible para toda la
aplicación sin tener que repetirlos. Además, alteraremos el orden de creación de forms en el
proyecto, entrando en Auto-create forms de las opciones del proyecto, situando en primer
lugar a nuestro módulo de datos. Haremos esto por lo siguiente: asociaremos al evento
onCreate código para abrir la conexión con la base de datos, estando así disponible desde el
principio de la aplicación y no después de crearse el form principal. Así, nos evitaremos
problemas en el caso de que antes de que se muestre el form principal sea necesario realizar
alguna operación con la base de datos.
Los módulos de datos se encuentran en Delphi accediendo a New -> Data Module, dentro de la
pestaña por defecto, New. Nuestra aplicación puede usar cuantos necesite. Puede ser buena idea,
incluso, usar distintos módulos de datos, atendiendo a finalidades distintas, para poner en ellos
los componentes no visuales, agrupados por esta finalidad.
4.i. TDatabase
El componente TDatabase nos va a permitir:
•
•
•
•
Crear conexiones persistentes a bases de datos (esto es, permaneceremos conectados a
la base de datos siempre que el componente tenga especificado que debe estar
conectado).
Personalizar el acceso a servidores de bases de datos. Por ejemplo, solicitar o no una
contraseña de acceso al conectar con la base de datos.
Controlar las transacciones y especificar sus niveles de aislamiento (aunque en este
curso no vamos a hablar de transacciones).
Crear alias BDE locales de aplicaciones. Esto es especialmente útil por lo siguiente:
supongamos una aplicación que debe funcionar con una base de datos en una
determinada ruta. Todos los componentes de acceso a datos que necesite la aplicación,
deben estar ligados a esa base de datos vía el alias. Si, por algún motivo, cambia el
alias, entonces tendríamos que cambiarlo a todos los componentes de acceso a datos.
Teniendo definido un alias local, asociaremos a los componentes de acceso a datos el
alias local, y así, en caso de que haya que cambiar algo, sólo tendremos que hacerlo en
el componente TDatabase.
Vamos a estudiar las propiedades más importantes de este componente:
AliasName
El valor de esta propiedad será el alias BDE asociado. Delphi nos presentará un
menú desplegable con los alias definidos en el sistema. De ahí será de donde
tendremos que escoger uno. Si damos un valor a la propiedad DriverName
entonces se elimina el valor dado a esta propiedad.
DriverName
Identifica al controlador BDE del componente (esto forma parte del alias). Es
autoexcluyente con AliasName, como hemos visto.
Connected
Es un booleano que nos dice si estamos conectados o no a la base de datos.
DatabaseName
Es el alias local a la aplicación que damos al componente. No es necesario, pero
sí recomendable darle uno.
LoginPrompt
Es un booleano que nos dice si se debe solicitar o no un nombre de usuario y su
contraseña la primera vez que se vaya a acceder a la base de datos. Si le damos
el valor False tendremos que especificar estos valores en la propiedad Params
Params
Se trata de una lista con los parámetros de acceso para la conexión.
Params
En el inspector de objetos, al situarnos sobre la propiedad Params, podemos hacer doble click
con el ratón, con lo que se abre la siguiente ventana:
En ella escribiremos lo siguiente:
USER NAME=ElNombreDelUsuario
PASSWORD=LaClaveDelUsuario
cuando pongamos a False el valor de la propiedad LoginPrompt
Resumiendo:
Cuando vayamos a realizar una aplicación de base de datos, comenzaremos creando un form de
módulo de datos (un DataModule) en el que incluiremos el componente TDatabase. Pondremos
los valores oportunos en sus propiedades, y le daremos un valor a la propiedad DatabaseName
para tener definido un alias local. Veremos en los siguientes capítulos la utilidad de ese alias
local. Para poder asociar a los componentes de acceso a datos este alias local, tendremos que
estar conectados a la base de datos. En tiempo de diseño podremos conseguirlo poniendo el
valor de la propiedad Connected a True. En tiempo de ejecución también podemos acudir al
método Open del componente. Será conveniente protegerlo con un bloque try .. except por si
se produjera algún problema en la apertura de la base de datos.
4.ii. TDataSet
Este componente es el que encapsula los datos de una base de datos. No debemos usarlo
directamente en nuestras aplicaciones. Para ello, tenemos a sus descendientes, los componentes
de acceso a datos TTable, TQuery y TStoredProc. Sin embargo, debemos conocer bien este
componente, pues es el que nos prové de propiedades y métodos comunes a sus descendientes,
fundamentales para el acceso a datos.
Además, cada conjunto de datos debe tener asociado su componente TDataSource
correspondiente, que es el que vincula los controles de datos visuales con los conjuntos de
datos. El componente de fuente de datos es el que se encarga de canalizar los datos desde el
componente de acceso a datos al componente visual.
Así que vamos a comentar las características interesantes que nos ofrece este componente
(recordemos que serán comunes a sus descendientes):
En primer lugar, tenemos que saber cómo abrir y cerrar conjuntos de datos. Mientras un
conjunto de datos esté cerrado, no podremos extraer datos de él. Esto se traduce en que los
componentes visuales que estén asociados a él (vía un TDataSource) no mostrarán datos. Así,
cuando esté abierto, sí se podrán ver los datos, e igualmente se podrá recorrer las distintas filas
que pueda contener.
Por tanto, para abrir el conjunto de datos tenemos dos posibilidades que son equivalentes:
CompDescDeTDataSet.Active := True;
{ diseño y ejecución }
CompDescDeTDataSet.Open;
{ ejecución }
Y para cerrarlo tenemos otras dos, igualmente equivalentes:
CompDescDeTDataSet.Active := False; { diseño y ejecución }
CompDescDeTDataSet.Close;
{ ejecución }
Si hay que modificar alguna propiedad del conjunto de datos que afecte a la consulta, es
necesario cerrar ANTES dicho conjunto.
Vamos a ver ahora cómo nos desplazamos por conjuntos de datos:
Cada conjunto de datos tiene un cursor (es decir, un puntero que apunta a la fila ACTUAL del
conjunto). Dicha fila corresponde a los valores que pueden manipularse vía métodos de
edición/inserción/borrado, y cuyos valores de campo muestran actualmente controles de dato
monocampo, como TDBEdit o TDBText.
Disponemos de los siguientes métodos para desplazarnos por conjuntos de datos:
First
Desplaza el cursor a la primera fila del conjunto de datos
Last
Desplaza el cursor a la última fila del conjunto de datos
Next
Desplaza el cursor a la fila siguiente del conjunto de datos
Prior
Desplaza el cursor a la fila anterior del conjunto de datos
MoveBy(NumFilas:
Integer)
Desplaza el cursor un número dado de filas del conjunto de datos,
hacia delante si NumFilas es positivo, y hacia atrás si NumFilas es
negativo
El objeto TDataSet cuenta además con las propiedades:
BOF (beginning of file)
Es TRUE si:
•
•
•
•
Se
Se
Se
Se
abre el conjunto de datos
llama al método First del conjunto de datos
llama a Prior y falla (porque el cursor ya está en la primera fila)
llama a SetRange en un rango o conjunto de datos vacío (no veremos SetRange)
Es FALSE en todos los demás casos.
EOF (end of file)
Es TRUE si:
•
•
•
•
Se
Se
Se
Se
abre un conjunto de datos vacío
llama al método Last del conjunto de datos
llama a Next y falla (porque el cursor ya está en la última fila)
llama a SetRange en un rango o conjunto de datos vacío (no veremos SetRange)
Es FALSE en todos los demás casos.
Marcadores
Un marcador es un objeto que nos va a permitir marcar una posición concreta del conjunto de
datos, de manera que si nos movemos después por dicho conjunto, podamos más adelante
volver a esta posición marcada. Para ello, Delphi cuenta con tres métodos marcador que
permiten asignar un indicador a un registro de un conjunto de datos para volver al mismo
posteriormente (es decir, marcamos una posición concreta):
•
•
•
GetBookmark: asigna un marcador a la posición actual en el conjunto de datos
GotoBookmark: volver a un marcador creado previamente con GetBookmark
FreeBookmark: libera un marcador creado previamente con GetBookmark
Para crear un marcador es necesario declarar una variable de tipo TBookmark. Se trata de un
puntero, así que tanto para liberarla definitivamente como para usarla para marcar otro registro,
hemos de llamar a FreeBookmark.
Por ejemplo:
PROCEDURE HazAlgo(CONST Tbl: TTable);
VAR
B: TBookmark;
BEGIN
B := Tbl.GetBookmark;
Tbl.DisableControls;
TRY
Tbl.First;
WHILE NOT Tbl.EOF DO
BEGIN
{ Proceso }
Tbl.Next;
END;
FINALLY
Tbl.GotoBookmark(B);
Tbl.EnableControls;
Tbl.FreeBookmark(B);
END;
END;
Este código consta de un procedimiento al que le pasamos como argumento un objeto de tipo
TTable (uno de los descendientes de TDataSet). Declaramos una variable de tipo TBookmark y
marcamos la posición actual de la tabla (será la que estuviera apuntada en ese momento por el
cursor, no tiene por qué ser la primera). Nos vamos al principio de la tabla (usando el método
First) y mientras no lleguemos al final (usando la propiedad EOF), procesamos lo que haya que
procesar de la fila actual, y avanzamos el cursor (usando el método Next). Terminado el
proceso, volvemos a la posición marcada inicialmente y liberamos el marcador. Todo esto va
englobado dentro de un bloque TRY ... FINALLY porque hemos de asegurarnos de que el
marcador se libera. Nuestro proceso podría dar lugar a una excepción, así que hemos de ser
cuidadosos.
Para buscar datos dentro de un conjunto de datos usaremos la siguiente función:
FUNCTION TDescDeTDataSet.Locate('Campo; ...; Campo',
VarArrayOf([Valor1, ..., ValorN]), SearchOptions): Boolean;
Especificamos los campos, los valores a buscar como un array de variants (por eso he puesto
que el segundo parámetro es VarArrayOf, pero si hubiera un único campo no haría falta
convertirlo a array de variant) y un conjunto de opciones de búsqueda que podeis consultar en
la ayuda. Devuelve si ha tenido éxito o no con la búsqueda. De todas formas, cuando veamos el
componente TQuery, casi con toda seguridad no le encontraremos mucha utilidad a esta función,
pues en el componente TQuery podremos restringir la selección de datos tanto como queramos
usando sentencias SQL.
Modificación de datos del conjunto de datos
Otro punto importante es saber cómo modificar los datos existentes en un conjunto de datos.
Para ello, contamos con los siguientes métodos:
Edit
Asigna al conjunto de datos el estado dsEdit, si es que el conjunto no está ya en ese
estado, o si está en modo dsInsert. Entonces, podremos editar datos.
Append
Almacena los datos pendientes, desplaza el registro actual al final del conjunto de datos,
y asigna al conjunto de datos el estado dsInsert.
Insert
Almacena los datos pendientes y asigna al conjunto el estado dsInsert.
Post
Intenta almacenar el nuevo registro, o modificar el registro existente, en la base de
datos. Si hay éxito, se asigna al conjunto de datos el estado dsBrowse. Si no, se
mantiene el estado.
Cancel
Cancela la operación actual y asigna al conjunto el estado dsBrowse.
Delete
Elimina el registro actual y asigna al conjunto de datos el estado dsBrowse.
Por ejemplo:
Tbl.Edit;
Tbl.FieldValues['Campo'] := Valor;
Tbl.Post;
Ponemos la tabla para editar, usamos la propiedad FieldValues para acceder al campo Campo, y
almacenamos en este campo el valor Valor. A continuación, usando el método Post cerramos la
edición, almacenándose los datos.
Previo al estudio de los descendientes de TDataSet será necesario estudiar los componentes de
campo, que se engloban en el objeto TField. Este objeto da formas de acceder a los campos
individuales de un conjunto de datos. Todos los componentes de conjunto de datos cuentan con
tantos objetos TField como campos tenga la tabla/consulta/etc. Los veremos en capítulo
aparte.
Dentro del objeto TDataSet, hay un evento que cabe destacar, el evento OnCalcFields, que nos
sirve para decidir los valores de los llamados campos calculados en función de los valores de los
campos normales. Si la propiedad AutoCalcFields del conjunto de datos es TRUE, entonces se
produce un evento OnCalcFields si:
•
•
•
Hay un conjunto de datos abierto
El foco se desplaza de un componente visual a otro, o de una columna a otra en un
TDBGrid (rejilla de datos)
Se recupera un registro de la base de datos
Si el valor de un campo no calculado cambia, se llama a este evento independientemente de si
AutoCalcFields es TRUE o FALSE. Veremos en el capítulo dedicado a TField qué es un campo
calculado, y qué es un campo no calculado.
Hay que tener cuidado con este evento y no llamar a Post dentro del código del manejador del
evento: aunque AutoCalcFields es FALSE, OnCalcFields es llamado si hay un Post. Hacer
Post en el evento sería recursivo y habria desbordamiento de pila.
¿Resulta confuso todo esto? Quizá un poco. Hay que tener en cuenta que llegados a este punto
aún no hemos visto cómo llevar a la práctica este componente que no vamos a tratar
directamente, ni cómo usarlo exactamente, ni cómo podemos mostrar los datos, ni...
No hay que olvidarlo: no usaremos este componente sino sus descendientes, y todo lo que
hemos visto aquí es puramente teórico pero imprescindible para avanzar. Es en los siguientes
capítulos donde se empieza a manipular de lo que se habla aquí.
4.iii. TDataSource
Se trata de un componente de base de datos no visual que sirve de conducto entre un conjunto
de datos y un componente de visualización de datos en un form. Es necesario que cada control
de datos esté asociado a un componente TDataSource para poder manipular y visualizar los
datos.
Propiedades interesantes
DataSet
Especifica el nombre del conjunto de datos del que este componente obtiene los datos.
Puede también asignarse a un conjunto de datos de otro form para sincronizar los
componentes de visualización de datos de los dos forms.
Enabled
Nos dice si está conectado a un conjunto de datos.
AutoEdit
Especifica si los conjunto de datos conectados al TDataSource entran automáticamente
en modo Edit cuando el usuario empieza a introducir los componentes de visualización
vinculados al conjunto de datos.
Eventos interesantes
OnDataChange
Este evento se da cada vez que el cursor se desplaza a un nuevo registro. Si se llama al
método Next, Previous, Insert o cualquier otro que implique un cambio de posición del
cursor, se llamará a este evento.
OnUpdateData
Se produce cada vez que los datos están a punto de actualizarse, es decir, tras llamadas
a Post pero antes de que los datos se almacenen definitivamente en la base de datos.
OnStateChange
Se produce cada vez que cambia el estado del conjunto de datos asociado al
TDataSource.
Veremos su utilidad cuando estudiemos los componentes gráficos, pues es en ese momento
cuando hay que elegir un descendiente adecuado de TDataSet, asociarle un TDataSource para,
en el componente gráfico, asociar el mismo TDataSource. Entonces tendremos conectados el
componente gráfico con el TDataSet vía el TDataSource.
4.iv. TField: Uso de campos
Vamos a ver en este capítulo un objeto muy importante y útil, el objeto TField. Este objeto
representa columnas de bases de datos individuales en conjuntos de datos. No lo usaremos
directamente en nuestras aplicaciones, sino que emplearemos sus componentes descendientes.
Cada uno de ellos representa un tipo de dato distinto en una columna del TDataSet
correspondiente al componente de conjunto de datos. Estos tipos son:
Nombre del componente Nombre del componente Nombre del componente
TStringField
TSmallIntField
TIntegerField
TBooleanField
TFloatField
TCurrencyField
TDateField
TTimeField
TDateTimeField
TVarBytesField
TBlobField
TMemoField
TWordField
TBCDField
TBytesField
TGraphicsField
TAutoIncField
TNumericField
Este componente no es visual, y tampoco está visible en tiempo de diseño. Los TField están
asociados a un componente de conjunto de datos y dan a componentes de datos como TDBGrid
acceso a ciertas columnas de bases de datos vía ese conjunto.
Aunque se verá más adelante, voy a intentar explicar esto de forma más inteligible. Como ya
sabemos, en una aplicación de base de datos tenemos, por una parte, componentes visuales que
mostrarán los datos y nos dejarán cambiarlos y, por otra parte, componentes no visuales que
obtienen los datos a mostrar. En medio tenemos a TDataSource, que es el conducto entre unos
y otros, el que realiza el paso efectivo de la información. Podemos tener un control visual en que
queramos mostrar varias columnas fijas de una determinada consulta. Bien, pues TField va a
ser nuestro aliado. Definiremos lo que se llaman campos persistentes que podrán ser
referenciados desde el componente visual para poder fijar las columnas a mostrar. Lo iremos
viendo poco a poco.
Al abrirse un conjunto de datos, se genera un componente de campo para cada columna de
datos de la tabla o consulta correspondiente. Delphi usa BDE para determinar el tipo correcto de
componente de campo que se debe asignar a cada columna (los que hemos visto en la tabla).
Este tipo, además, determina las propiedades del campo así como cómo debe mostrarse. Por
ejemplo, si se da el caso de que para una columna se genera un TFloatField, entonces
tendremos una propiedad que nos permitirá decirle el formato que queremos de visualización. Si
es, por ejemplo, de dos decimales, este formato sería 0.00#. También podríamos fijar el número
de dígitos a mostrar. Es sólo un ejemplo. Como veremos, los componentes de campo tienen
propiedades comunes, y luego habrá otras específicas del tipo de campo que sea.
En modo de diseño, estos componentes se crean de forma dinámica si el correspondiente
conjunto de datos tiene a True su propiedad Active. En tiempo de ejecución también se
generan de forma dinámica. No obstante, es recomendado crear componentes de campo
persistentes. Si, por ejemplo, tenemos un control TDBGrid que se basa en una estimación del
número de campos, al añadir uno nuevo la aplicación podría responder de forma "extraña". Pero
si el número de campos viene definido de antemano, estos problemas no se dan. Estos campos
definidos "de antemano" son los que llamamos campos persistentes.
Entre otras ventajas, nos ofrecen las siguientes:
•
Restricción de los campos del conjunto de datos a un subconjunto de las columnas
disponibles en la base de datos correspondiente.
•
•
•
Definición de nuevos campos basándose en columnas de la tabla o consulta
correspondiente al conjunto de datos.
Definición de campos calculados.
Modificación de las propiedades de edición y visualización de los componentes de campo.
Con los componentes de campo persistentes tenemos garantizado que cada vez que se ejecute
la aplicación se usarán y mostrarán las mismas columnas, en el mismo orden, incluso si ha
cambiado la estructura física de la base de datos.
Cómo se crean
Para crearlos usaremos el editor de campos. Se inicia haciendo doble click sobre un componente
de conjunto de datos (un descendiente de TDataSet). Presenta el siguiente aspecto:
También podemos acceder a él pulsando con el botón derecho del ratón sobre el componente de
conjunto de datos y escogiendo la opción "Fields Editor" que se nos mostrará en el menú
contextual. Notar que en la barra de título pone
NombreForm.NombreComponenteConjuntoDeDatos.
Ahora tenemos que añadir aquí los campos que queramos que sean persistentes. Para ello,
pulsamos con el botón derecho del ratón sobre el Editor de Campos, con lo que aparece el
menú:
Entonces nos aparece una lista con todos los campos disponibles. Por ejemplo:
Los campos que nos aparecen son los correspondientes a la tabla seleccionada (si elegimos
como componente conjunto de datos TTable) o a la consulta SQL (si elegimos TQuery). En este
ejemplo, los campos son los resultantes de una consulta SQL en un componente de tipo TQuery.
Si no termináis de verlo claro, en el ejemplo desarrollado de la agenda iremos viendo paso a
paso qué es lo que debemos hacer y por qué.
Podemos crear nuevos campos o eliminar campos que hayamos puesto en la lista. Además,
podemos ordenarlos como queramos, pinchando sobre el campo a cambiar de sitio y
arrastrándolo a la nueva posición.
Para crear un campo nuevo (es decir, uno que no existe y por tanto no aparece en la lista de
campos disponibles) pulsaremos con el botón derecho del ratón sobre el Editor de Campos y
elegiremos la opción New Field... del menú contextual. Se nos abrirá una ventana como esta:
Vamos a estudiar únicamente los dos primeros tipos de campo, Data y Calculated. El tercer
tipo, Lookup puede ser estudiado como ejercicio buscando en la ayuda de Delphi (si no lo he
dicho ya, la ayuda de Delphi es muy completa y un buen lugar donde encontrar documentación
de forma estructurada; además, es muy buena en general).
Definición de campos de datos
Imaginad que quereis cambiar, por el motivo que sea, el tipo de dato de un campo. Por ejemplo,
teneis un campo de tipo TSmallIntField y queréis convertirlo en TIntegerField. Dado que no
podemos cambiar el tipo de dato de forma directa, tendremos que usar un campo de este tipo
para substituir al existente. Los pasos a seguir (en la ventana que hemos visto antes) son:
1.
2.
3.
4.
En primer lugar, hemos de asegurarnos que en el apartado Field type tenemos
seleccionado Data.
Introducimos como nombre de campo el nombre de un campo persistente que exista
(aquel del que queremos cambiar su tipo) en el campo Name. No hemos de introducir un
nombre nuevo, sino uno que exista.
Elegir el nuevo tipo de dato seleccionándolo del combo Type.
Introducir el tamaño del campo en la opción Size si es necesario (en los tipos
TStringField, TBytesField y TVarBytesField).
Con todos los datos necesarios introducidos, ya podemos pulsar el botón OK. Ya tenemos
definido nuestro campo; podremos cambiar sus propiedades en el Inspector de Objetos.
Definición de campos calculados
Un campo calculado nos muestra valores que el evento OnCalcFields del objeto conjunto de
datos calcula en tiempo de ejecución. Para crear un campo calculado, seguiremos los siguientes
pasos:
1.
2.
3.
4.
En primer lugar, nos aseguraremos de que en el apartado Field type tenemos
seleccionado Calculated.
Elegimos el tipo de datos seleccionándolo del combo Type.
Le damos un nombre en el campo Name. Hemos de introducir un nombre nuevo, no el de
un campo que ya exista.
Introducir el tamaño en Size si es necesario.
Con todo esto, pulsamos OK y ya tenemos creado nuestro campo calculado. Ahora habrá que
acudir al evento OnCalcFields del conjunto de datos correspondiente y escribir el código que
asignará un valor a nuestro campo calculado.
Algunas propiedades de los componentes de campo
Propiedad
Breve descripción
Aligment
Nos permite alinear a la izquierda, derecha o centro el
contenido del campo
Calculated
Si es True nos indica que el contenido del campo es
calculado en el evento onCalcFields del respectivo
componente fuente de datos.
DisplayFormat
Especifica el formato de los datos que se muestran (no
disponible para todos los tipos de campo).
DisplayWidth
Ancho, en caracteres, de una columna de un TDBGrid que
muestra el campo.
FieldName
Especifica el nombre de la columna real de la tabla de la que
el campo toma sus datos.
ReadOnly
Si es True muestra los valores del campo, pero no permite
editarlos.
Por ejemplo, un componente de campo de tipo TStringField no cuenta con la propiedad
DisplayFormat.
Cuando hagáis vuestras propias aplicaciones os daréis cuenta de que si teneis un componente de
conjunto de datos, llamémosle ConjuntoDeDatos, cuando creéis un campo persistente, por
ejemplo CAMPO_PERSISTENTE, el objeto de campo que se crea recibe el identificador (el nombre
para Delphi) ConjuntoDeDatosCAMPO_PERSISTENTE.
En una aplicación, podemos acceder al valor de una columna de la base de datos vía la
propiedad Value del componente de campo correspondiente haciendo (por ejemplo):
EdNombreAlumno.Text := ConjuntoDeDatosNOMBRE_ALUMNO.Value;
Esto va bien para las cadenas, pero en otros tipos de campos será necesario hacer una
conversión; para ello, el componente de campo dispone de unos métodos que nos permitirá
hacer esta conversión. Vamos a ver una tabla en la que mostramos estas funciones de
conversión y apuntamos el tipo de campo para el que dicha función va bien:
Tipo de
campo /
función
AsVariant AsString AsInteger AsFloat AsCurrency AsDateTime AsBoolean
TStringField
OK
OK
OK
OK
OK
OK
TIntegerField
OK
OK
OK
OK
OK
TSmallIntField
OK
OK
OK
OK
OK
TWordField
OK
OK
OK
OK
OK
TFloatField
OK
OK
OK
OK
TCurrencyField OK
OK
OK
TBCDField
OK
OK
OK
TDateTimeField OK
OK
OK
OK
OK
TDateField
OK
OK
OK
OK
OK
TTimeField
OK
OK
OK
OK
OK
TBooleanField
OK
OK
TBytesField
OK
OK
TVarBytesField OK
OK
TBlobField
OK
OK
TMemoField
OK
OK
OK
OK
TGraphicField
OK
OK
En caso de duda, usar AsVariant.
Vamos a hacer un pequeño inciso mostrando el resultado de algunas conversiones "especiales":
De String a Boolean: Únicamente convierte los valores "True" o "Yes" a True y los valores
"False" o "No" a False. El resto genera excepciones.
De Float a Integer: Redondea al entero más cercano.
De DateTime a Float: Convierte fechas al número de días transcurridos desde el 31 de
diciembre de 1899 y las horas a una fracción de 24 horas.
De Boolean a String: Convierte True a "True" y False a "False".
En cualquier caso, una conversión no válida generará una excepción.
Varios ejemplos de uso:
EdNombre.Text := ConjuntoDeDatosNOMBRE_ALUMNO.AsString;
EdApellidos.Text := ConjuntoDeDatosAPELLIDOS_ALUMNO.AsString;
DTPickerFechaNac.Date := ConjuntoDeDatosFECHA_NAC_ALUMNO.AsDate;
Curso := ConjuntoDeDatosCURSO_ALUMNO.AsInteger;
ConjuntoDeDatosREPETIDOR_ALUMNO.AsBoolean := ChkBxRepetidor.Checked;
Otras formas de acceder a los campos:
También podemos acceder a los valores de los campos vía la propiedad Fields del objeto de
conjunto de datos. Esta propiedad es de tipo array, por lo que necesitaremos saber la posición
de un campo en el objeto conjunto de datos, siendo la primera columna la 0.
Por ejemplo: EdNombre.Text := ConjuntoDeDatos.Fields[2].AsString;
Esto sería si supiéramos que la tercera columna es la del nombre. Una alternativa que evita
saber el orden correcto es usar el método FieldByName. Así, lo siguiente sería equivalente al
ejemplo anterior:
EdNombre.Text := ConjuntoDeDatos.FieldByName('NOMBRE_ALUMNO').AsString;
4.v. TTable
Gracias a este componente vamos a poder trabajar con los datos de cualquier fila y columna de
una tabla concreta de la base de datos. Hemos de recordar que es un descendiente de
TDataSet, así que todo lo dicho para TDataSet es válido para TTable.
Creación de un componente TTable
Siempre que queramos usar un componente TTable, los pasos fundamentales a seguir son
estos:
1.
2.
3.
4.
Insertar el componente bien en un form bien en un Data Module y darle nombre en
Name.
Definir en la propiedad DatabaseName la base de datos a la que estará ligado.
Definir en la propiedad TableName el nombre de la tabla a la que hará referencia.
Insertar un componente TDataSource en el form o en el Data Module y asignar a su
propiedad DataSet el nombre de la tabla (i.e., su propiedad Name).
Nota: DatabaseName puede ser un alias de BDE (aparecerá en un desplegable junto a esta
propiedad) o bien una ruta completa. Es recomendable que sea un alias BDE porque si
cambiamos la base de datos de sitio, sólo tendremos que cambiar en el alias este dato y no en
todos los componentes que hagan referencia a ella. Es más recomendable aún que sea el
nombre de algún componente TDatabase que exista en la aplicación, porque si cambiara el alias,
únicamente habría que cambiarlo aquí.
Búsqueda de registros
Para buscar registros usaremos el método Locate ya visto en la explicación de TDataSet. Este
método nos desplazará el cursor a la primera fila que coincide con el conjunto de criterios de
búsqueda especificados. Un ejemplo puede ser:
Exito := Tabla.Locate('NOMBRE_ALUMNO', 'Juan', [loPartialKey]);
No hay mucho más que decir; el resto ya fue estudiado con TDataSet.
4.vi. TQuery
Este componente puede usarse con servidores de bases de datos remotos (en la version
Client/Server Suite de Delphi), con bases de datos Paradox y dBase y con bases de datos
compatibles con ODBC (como Access). Gracias a este componente vamos a poder acceder a
varias tablas al mismo tiempo (vía un JOIN, claro está) o acceder de forma automática a un
subconjunto de filas y columas de una tabla o tablas. Hemos de recordar que también es un
descendiente de TDataSet, así que todo lo dicho para TDataSet es válido para TQuery.
Los criterios de selección son sentencias SQL y pueden ser estáticos (todos los parámetros de
la sentencia se dan en tiempo de diseño) o dinámicos (algunos o todos los parámetros se dan
en tiempo de ejecución).
Creación de un componente TQuery
Siempre que queramos usar un componente TQuery, los pasos fundamentales a seguir son
estos:
1.
Insertar en el componente bien en un form bien en un Data Module y darle nombre en
Name.
2. Definir en la propiedad DatabaseName la base de datos a la que estará ligado.
3. Especificar la sentencia SQL en la propiedad SQL del componente y definir, si es
necesario, los parámetros de la misma en la propiedad Params.
4. Insertar un componente TDataSource en el form o en el Data Module y asignar a su
propiedad DataSet el nombre del query (i.e., su propiedad Name).
Consultas estáticas y dinámicas
Vamos a distinguirlas con un ejemplo. Supongamos que escribimos en la propiedad SQL
(veremos a continuación cómo asignar valores a esta propiedad) el texto:
SELECT NOMBRE_ALUMNO FROM ALUMNOS WHERE NOTAMEDIA >= 5 AND EDAD = 15
Todos los valores para la cláusula WHERE vienen dados de forma explícita. Es una consulta
estática, porque todos los valores vienen dados. Sin embargo, si en vez de eso escribiéramos:
SELECT NOMBRE_ALUMNO FROM ALUMNOS WHERE NOTAMEDIA >= 5 AND EDAD = :Edad
Vemos que aparece, en vez de un valor concreto para la edad, el valor :Edad. Eso quiere decir
que en tiempo de ejecución, de acuerdo a los criterios que exija nuestro programa, asignaremos
el valor adecuado de la edad según la situación. La forma de especificar estos nombres variables
es anteponiendo dos puntos al nombre que le queramos dar. Luego, en el código, asignaremos
el valor adecuado usando el método ParamByName del componente TQuery. Por ejemplo, para
nuestro caso anterior podría quedar como sigue:
QAlumnos.ParamByName('Edad').AsInteger := 17;
Notar que el nombre del parámetro, en la llamada al método ParamByName, no lleva los dos
puntos. Los dos puntos se ponen única y exclusivamente en la consulta, para distinguirlos de un
valor estático y para saber que el identificador que va a continuación es el que se debe esperar
en el programa.
Dónde especificar la consulta SQL
El componente TQuery tiene una propiedad llamada SQL que es donde se almacena la consulta a
enviar a la base de datos. Podemos introducirla en tiempo de diseño pulsando sobre ella (se nos
abre el editor de consultas) o en tiempo de ejecución, asignando a la propiedad Text de la
propiedad SQL el texto completo de la consulta. Hay que señalar que esta propiedad SQL es de
tipo TStringList, por ello contamos con una propiedad Text así como el resto de propiedades
de estos objetos. En tiempo de ejecución, antes de asignar cualquier valor a la propiedad SQL la
consulta debe estar cerrada. Esto lo conseguimos con el método Close que ya estudiamos en el
objeto TDataSet. Así, un ejemplo de asignación en tiempo de ejecución puede ser:
QAlumnos.Close;
QAlumnos.SQL.Text := 'SELECT NOMBRE_ALUMNO FROM ALUMNOS WHERE EDAD = 15';
Para más información, repasad TDataSet y consultad en la ayuda de Delphi.
5.i. TDBGrid
Este componente nos permite mostrar los registros de un TDataSet en forma tabular:
Para asociar este componente con el TDataSet del que obtiene los datos, hemos de poner en su
propiedad DataSource el nombre del TDataSource asociado al TDataSet. Si la propiedad State
del DBGrid toma el valor csDefault, el aspecto de los registros se determina a través de las
propiedades de los campos incluidos en el TDataSet asociado al DBGrid.
Si el TDataSet asociado al DBGrid consta de componentes de campo persistentes (ya vimos
cómo crearlos en el capítulo correspondiente), éstos permanecen aunque se cierre el TDataSet,
de manera que las columnas asociadas a estos campos conservarán también sus propiedades
aunque se cierre el TDataSet.
Podemos personalizar una DBGrid precisamente gracias a los objetos de campo persistentes.
Así, en tiempo de diseño podremos dejar la DBGrid lista para que funcione exactamente como
queremos que se muestre siempre. La forma de hacerlo es la siguiente. En primer lugar, nos
vamos a la propiedad Columns y hacemos doble click sobre el botón de los puntos suspensivos.
Entonces se nos abre una ventana como la siguiente:
Añadimos tantas columnas como queramos pulsando New. En principio, todas ellas no están
asociadas a campos. Si pulsamos sobre una columna concreta, entonces en el Inspector de
objetos nos muestra todas las propiedades de esa columna. El título de la columna puede tener
su propio formato, independientemente del formato de la columna, pudiendo poner el título en
negrita de color clNavy y la columna en cursiva de color clMaroon con fondo clInfoBk. Hay una
propiedad que nos interesa mucho: FieldName. Si pulsamos, se nos abre un desplegable con
todos los componentes de campo persistentes que hayan sido definidos para el TDataSet.
Elegimos uno y ya está. Repetimos la operación con las restantes columnas, y ya tenemos el
DBGrid completamente personalizado.
Ejemplo: Creación de una agenda
I. Diseño de la base de datos y las operaciones
Como ejemplo de uso de base de datos con Delphi, vamos a acudir al socorrido ejercicio de
crearnos una agenda con los datos de nuestros conocidos. Para evitar simplificar demasiado con
una única tabla en la base de datos, añadiremos un pequeño extra en este ejemplo: los
contactos estarán agrupados por categorías, lo que nos da la siguiente estructura (podeis
añadir/eliminar los campos que queráis):
Como vamos a usar Interbase, primero crearemos la base de datos bajo el usuario que
queramos que sea su dueño. Si no sabeis dar de alta usuarios, o no sabeis crear la base de
datos, id al anexo sobre Interbase. Yo le voy a dar el nombre Agenda.gdb.
A continuación tenemos que crear las tablas. Podemos hacerlo directamente en el IBConsole, o
podemos crear un alias BDE y entonces crear las tablas con el SQL Explorer. Yo voy a hacerlo
usando la segunda opción, porque de todas maneras, necesitaremos el alias BDE para cuando
llegue el momento de diseñar la aplicación con Delphi. Recordad que en el anexo 1 encontrareis
la información necesaria para crear alias BDE y en el
SQL Explorer.
anexo 3 hay un pequeño manual de uso de
Elijáis el camino que elijáis, hay que crear las tablas, para lo cual vamos a introducir las
siguientes sentencias SQL:
CREATE TABLE CATEGORIAS(
IDCATEGORIA INTEGER NOT NULL,
DESCRIPCION VARCHAR(255) NOT NULL,
PRIMARY KEY(IDCATEGORIA)
);
CREATE GENERATOR GENIDCATEGORIA;
CREATE TABLE CONTACTOS(
IDCONTACTO INTEGER NOT NULL,
CATEGORIA INTEGER NOT NULL,
NOMBRE VARCHAR(100) NOT NULL,
APELLIDO1 VARCHAR(100) NOT NULL,
APELLIDO2 VARCHAR(100),
TELEFONO VARCHAR(20) NOT NULL,
MOVIL VARCHAR(20),
DIRECCION VARCHAR(255),
EMAIL1 VARCHAR(255),
EMAIL2 VARCHAR(255),
WEB1 VARCHAR(255),
WEB2 VARCHAR(255),
PRIMARY KEY(IDCONTACTO)
);
CREATE GENERATOR GENIDCONTACTO;
ALTER TABLE CONTACTOS
ADD FOREIGN KEY(CATEGORIA) REFERENCES CATEGORIAS(IDCATEGORIA);
Una vez introducidas, vamos a pensar en las operaciones básicas de gestión de estos datos:
inserción, edición, eliminación y búsqueda. Dejaremos claras cuáles serán las sentencias SQL
que llevarán a cabo cada una de las operaciones, con lo que el desarrollo del programa será más
sencillo.
Gestión de la tabla CATEGORIAS
Comenzaremos con la tabla CATEGORIAS. Entre otras cosas, empezamos por ella porque ningún
campo de esta tabla depende de que exista un valor previo en otra tabla (cosa que no sucede en
la tabla CONTACTOS). La clave primaria de esta tabla es IDCATEGORIA. Me gusta usar enteros
como claves primarias porque son más simples. Si estamos seguros de que la combinación
NOMBRE + APELLIDO1 + APELLIDO2 es única podríamos usarla como clave primaria, por
ejemplo. Personalmente, prefiero que la clave primaria sea un entero independiente del resto de
información. Es un criterio que he ido adoptando con el tiempo y que quizá vosotros veáis
innecesario.
Para generar los valores sucesivos de la clave primaria utilizo un generador, GENIDCATEGORIA. Le
pongo el prefijo GEN porque así lo identifico rápidamente como generador de los valores del
campo que le sigue, IDCATEGORIA en este caso. Así que vamos ya a ver en qué consisten las
operaciones básicas para esta tabla.
Inserción
Cuando se crea un generador, se inicializa automáticamente a 0. Así que, cuando insertemos un
nuevo registro, debemos incrementar este valor, e insertarlo junto con la descripción de la
categoría. Por tanto, las sentencias necesarias para insertar una nueva categoría serían:
INSERT INTO CATEGORIAS(
IDCATEGORIA
, DESCRIPCION
) VALUES (
GEN_ID(GENIDCATEGORIA, 1)
, :Descripcion
);
¿Qué es :Descripcion? Es un parámetro. Con eso quiero decir que la descripción a insertar será
la que se nos dé en el programa.
Edición
El único campo que podemos editar es la descripción de la categoría, ya que el ID permanece
invariable. Es un dato que al usuario no le sirve y que no le vamos a mostrar (el exceso de
información siempre es peligroso), pero que nosotros vamos a tener disponible (veremos cómo
cuando entremos en el desarrollo con Delphi, por ahora, asumimos que es así). Por tanto,
actualizar el registro será tan sencillo como:
UPDATE CATEGORIAS
SET DESCRIPCION = :Descripcion
WHERE IDCATEGORIA = :Id
;
Eliminación
Por supuesto, tras asegurarnos de que el usuario realmente quiere eliminar ese registro,
procederemos a realizar la operación de borrado:
DELETE FROM CATEGORIAS
WHERE IDCATEGORIA = :Id
Cuidado con la operación de borrar, si no pusiéramos la cláusula WHERE, se borraría la tabla
completa.
Búsqueda
Únicamente va a tener sentido buscar una categoría por su nombre. Una sentencia sencilla que
nos daría esto sería:
SELECT * FROM CATEGORIAS WHERE DESCRIPCION LIKE %LoQueBuscamos%
pero en lugar de eso, vamos a usar el método Locate de los descendientes de TDataSet.
Cuando desarrollemos la aplicación veremos que es bastante sencillo :-)
Gestión de la tabla CONTACTOS
Al contrario que con la otra tabla, ésta sí que depende de otra tabla. En el dibujo se ha mostrado
que hay una relación entre la tabla CONTACTOS y la tabla CATEGORIAS, y es que todo contacto
pertenece a una categoría, por ello, antes de crear un contacto, debe existir la categoría a la que
se le quiere asociar. Así, creadas las categorías necesarias, ya podemos dar de alta contactos.
Esta tabla también tiene como clave primaria un ID que será generado vía su generador
asociado GENIDCONTACTO por medio de la función GEN_ID que ya hemos usado. He elegido los
siguientes campos como obligatorios (especificado vía el NOT NULL que hay en la definición de
algunos campos): IDCONTACTO, CATEGORIA, NOMBRE, APELLIDO1, TELEFONO. No he escogido
APELLIDO2 porque no siempre sabemos el segundo apellido de una persona, y tampoco he
escogido MOVIL porque un contacto cualquiera en principio no tiene por qué tener móvil, pero sí
un TELEFONO, ya que la agenda se supone que es de teléfonos. Y la DIRECCION tampoco es
obligatoria porque no tenemos por qué saber dónde vive. Lo mismo con el resto de campos. Son
datos opcionales.
Inserción
Tras comprobar que los campos no nulos contienen valores, tendremos que escribir la siguiente
consulta de inserción (los campos opcionales los represento entre []):
INSERT INTO CONTACTOS(
IDCONTACTO, CATEGORIA, NOMBRE, APELLIDO1[, APELLIDO2]
, TELEFONO[, MOVIL][, DIRECCION][, EMAIL1][, EMAIL2]
[, WEB1][, WEB2]
) VALUES (
GEN_ID(GENIDCONTACTO), :Categoria, :Nombre, :Apellido1[, :Apellido2]
, :Telefono[, :Movil][, :Direccion][, :Email1][, :Email2]
[, :Web1][, :Web2]
);
Es obvio que de alguna manera hemos de conocer el IDCATEGORIA correcto para asociarlo al
campo CATEGORIA. No hay ningún problema: veremos cómo nos ayuda Delphi en este sentido.
Edición
La edición es semejante a la inserción y queda como ejercicio para el lector ;-)
No hay que preocuparse por cómo localizar los ID adecuados: Delphi sigue ayudándonos en este
trabajo.
Eliminación
Previo asegurarse de si de verdad se va a eliminar el registro o no, la sentencia para eliminar el
registro es análoga a la vista con las categorías y queda de nuevo como ejercicio ;-)
Búsqueda
Aquí podemos buscar por varios campos: por nombre, por apellido, por teléfono, ... al igual que
con la tabla de CATEGORIAS, dejaremos el trabajo de la búsqueda al método Locate de los
objetos descendientes de TDataSet ;-)
Seguimos en el próximo capítulo diseñando la parte gráfica de la aplicación. Estudiad todo lo que
hemos pensado hasta el momento, en particular, la relación entre las tablas.
Ejemplo: Creación de una agenda
II.I Diseño del interface de la aplicación: Categorías
Una vez pensada la estructura de la base de datos así como las operaciones a realizar, vamos a
diseñar el interface de la aplicación. Por variar un poco, vamos a crear un form con un
TPageControl que contendrá dos TTabSheet: uno será la ficha de contactos y otro será la ficha
de categorías:
Además, vamos a tener en un DataModule el componente TDatabase:
De las propiedades del TDatabase cabe destacar:
AliasName = Agenda
DatabaseName = DBGlobal
LoginPrompt = False
Name = DBGlobal
En el evento OnCreate del DataModule escribiremos este código:
procedure TDM.DataModuleCreate(Sender: TObject);
begin
DBGlobal.Params.Values['USERNAME'] := TuNombreDeUsuario;
DBGlobal.Params.Values['PASSWORD'] := TuContraseña;
try
DBGlobal.Open;
except
ShowMessage('Error abriendo la base de datos: cerrando aplicación');
Application.Terminate;
end;
end;
Para que reconozca ShowMessage debéis incluir la unit Dialogs, y para que reconozca al objeto
Application debéis incluir la unit Forms. Además, hemos de colocar esta unit dentro del fichero
del proyecto la primera de entre todos los forms que se crean. Así, lo primero que comprobamos
al arrancar es que podemos conectar con la base de datos; si es así, pues ya se crean los forms
y si no, se termina la aplicación.
Ahora que ya tenemos el DataModule con la base de datos, comenzaremos con la ficha de
categorías por ser la más sencilla:
Por partes: la idea de funcionamiento (que aplicaremos también a los contactos) es que no
vamos a crear categorías ni editarlas directamente sobre la DBGrid, sino que lo haremos aparte
(concretamente en un panel). Los botones de gestión son de tipo TSpeedButton y los he llamado
SBtnNuevo, SBtnEditar, SBtnEliminar, SBtnBuscar y SBtnOKBuscar. Cuando estemos editando
datos en el panel, estos botones se deshabilitarán y al revés, cuando no estemos editando será
el panel quien esté deshabilitado.
El panel inferior recibe el nombre de PnlEdicion, tiene Caption = '' y BevelOuter =
bvLowered. Dentro contiene los componentes que usaremos para crear nuevas categorías o
editar las existentes. Concretamente, tenemos el edit EdCategoria, el label LblTipoModif, que
nos dirá si estamos creando una nueva categoría o editando una existente y los TBitBtn
BtnAceptar y BtnCancelar.
Hemos colocado un DBGrid, DBGCategorias, un Table, TblCategorias y un DataSource,
DSCategorias. El DataSource tiene por valor en su propiedad DataSet = TblCategorias.
TblCategorias tiene en su propiedad DatabaseName = DBGlobal (debemos incluir la unit del
DataModule para que esté disponible) y en su propiedad TableName = CATEGORIAS. El DBGrid
tiene en su propiedad DataSource = DSCategorias y hemos definido una columna que
mostrará el valor del campo persistente DESCRIPCION (he añadido los dos campos de la tabla a
la lista de campos persistentes), por tanto, para esta columna, FieldName = DESCRIPCION.
Además, al DBGrid le hemos quitado la posibilidad de que pueda editarse sobre él, el indicador
de registro actual y que pueda cambiarse el tamaño de la columna.
Empezaremos definiendo qué debe suceder en los eventos OnShow y OnCreate. El código para
estos eventos será ampliado cuando trabajemos con la pestaña de contactos.
procedure TFrmAgenda.FormCreate(Sender: TObject);
begin
HabilitarPanelEdicion(False);
end;
procedure TFrmAgenda.FormShow(Sender: TObject);
begin
TblCategorias.Close;
TblCategorias.Open;
end;
Por otro lado, definimos los siguientes procedimientos que nos serán útiles para realizar la
gestión.
procedure TFrmAgenda.HabilitarBotonesGestion(Habilitar: Boolean);
begin
SBtnNuevo.Enabled := Habilitar;
SBtnEditar.Enabled := Habilitar;
SBtnEliminar.Enabled := Habilitar;
SBtnBuscar.Enabled := Habilitar;
end;
procedure TFrmAgenda.HabilitarPanelEdicion(Habilitar: Boolean);
var
i: Integer;
begin
PnlEdicion.Enabled := Habilitar;
for i := 0 to PnlEdicion.ControlCount - 1 do
PnlEdicion.Controls[i].Enabled := Habilitar;
VaciarCamposEdicion;
end;
procedure TFrmAgenda.CerrarEdicion;
begin
HabilitarPanelEdicion(False);
HabilitarBotonesGestion(True);
end;
procedure TFrmAgenda.VaciarCamposEdicion;
begin
EdCategoria.Text := '';
LblTipoModif.Caption := '';
end;
procedure TFrmAgenda.RefrescarCategorias(Id: Integer);
begin
TblCategorias.Close;
TblCategorias.Open;
if Id > 0 then
begin
TblCategorias.Locate('IDCATEGORIA', Id, []);
DBGCategorias.SetFocus;
end;
end;
Ahora vamos a definir los procedimientos de crear, editar y eliminar registros. La idea será que
los botones Nuevo y Editar pondrán los valores pertinentes en los campos y luego, al pulsar el
botón Aceptar, en función de una variable que llamaremos GestionNuevo: Boolean (privada
dentro de la definición del form) sabremos si tenemos que hacer un INSERT o un UPDATE. El
botón de Cancelar simplemente vaciará el edit del panel de edición y retornará el control a los
botones de gestión. Para Eliminar primero pediremos confirmación.
Vamos primero a crear una nueva tabla en la base de datos, cuya definición será:
CREATE TABLE AUXILIAR(
COLUMNA INTEGER
);
La usaremos para incrementar el valor del generador para los ids, tanto de categorías como de
contactos. Debemos insertar una única fila en esta tabla pudiendo contener cualquier valor
entero, por ejemplo, 1. Este detalle es muy importante; lo que haremos a continuación no
funcionará si esta tabla no tiene una y sólo una fila con un valor numérico cualquiera. Recordad
que en la estructura de la base de datos se vio que hay un id en cada tabla que es único. Este id
es el que nos permite distinguir un registro de otro. Además, incluimos en el form un objeto
TQuery al que llamaremos QConsulta en cuya propiedad DatabaseName pondremos el valor
DBGlobal. Este query nos servirá para realizar la consulta siguiente:
SELECT GEN_ID(GENIDCATEGORIA, 1) FROM AUXILIAR;
que nos devolverá el siguiente valor a insertar del generador. Así, creamos la siguiente función:
function TFrmAgenda.GenID(Generador: String): Integer;
begin
QConsulta.Close;
QConsulta.SQL.Text := 'SELECT GEN_ID(' + Generador + ', 1) FROM AUXILIAR;';
QConsulta.Open;
Result := QConsulta.Fields[0].AsInteger;
end;
que usaremos en el lugar apropiado. Vamos a ver ahora cómo preparamos los controles según si
pulsamos el botón Nuevo o el botón Editar:
procedure TFrmAgenda.SBtnNuevoClick(Sender: TObject);
begin
GestionNuevo := True;
HabilitarPanelEdicion(True);
HabilitarBotonesGestion(False);
LblTipoModif.Caption := 'Nueva categoría';
EdCategoria.SetFocus;
end;
procedure TFrmAgenda.SBtnEditarClick(Sender: TObject);
begin
if TblCategoriasIDCATEGORIA.AsInteger > 0 then
begin
GestionNuevo := False;
HabilitarPanelEdicion(True);
HabilitarBotonesGestion(False);
LblTipoModif.Caption := 'Editando categoría';
EdCategoria.Text := TblCategoriasDESCRIPCION.AsString;
end;
end;
Como podeis ver, en Editar la condición dice que si no hay ids (es decir, no hay registros,
porque cuando se crea el primer registro su id es 1) entonces no hace nada, pero si hay ids,
preparo el edit del panel de edición con el valor del campo seleccionado.
Al pulsar el botón Eliminar ejecutaremos la siguiente acción:
procedure TFrmAgenda.SBtnEliminarClick(Sender: TObject);
var
Id: Integer;
begin
Id := TblCategoriasIDCATEGORIA.AsInteger;
if (Id > 0) and (
Application.MessageBox('¿Está seguro de que desea eliminar el registro
seleccionado?',
'Eliminar registro',
MB_YESNO + MB_ICONQUESTION
) = IDYES
) then
begin
TblCategorias.Delete;
RefrescarCategorias(0);
end;
end;
Si pulsamos el botón Cancelar tendremos:
procedure TFrmAgenda.BtnCancelarClick(Sender: TObject);
begin
if Application.MessageBox('¿Está seguro de que desea cancelar la edición de los
datos?',
'Confirmación de cancelación',
MB_YESNO + MB_ICONQUESTION
) = IDYES then
CerrarEdicion;
end;
Y si pulsamos Aceptar:
procedure TFrmAgenda.BtnAceptarClick(Sender: TObject);
var
Id: Integer;
begin
if GestionNuevo then
begin
Id := GenID('GENIDCATEGORIA');
TblCategorias.Close;
TblCategorias.Open;
TblCategorias.Insert;
TblCategoriasIDCATEGORIA.AsInteger := Id;
TblCategoriasDESCRIPCION.AsString := EdCategoria.Text;
TblCategorias.Post;
RefrescarCategorias(Id);
CerrarEdicion;
end
else
{ not GestionNuevo -> Editando existente }
begin
Id := TblCategoriasIDCATEGORIA.AsInteger;
TblCategorias.Edit;
TblCategoriasDESCRIPCION.AsString := EdCategoria.Text;
TblCategorias.Post;
RefrescarCategorias(Id);
CerrarEdicion;
end;
end;
Aquí tenemos un ejemplo de la aplicación funcionando:
Por último, tratamos la búsqueda. Para la búsqueda, en primer lugar pondremos, en tiempo de
diseño, la propiedad Enabled del botón OK a False. Después, al botón buscar le asignaremos
AllowAllUp = True y GroupIndex = 1. A continuación, escribimos el siguiente código para el
botón Buscar:
procedure TFrmAgenda.SBtnBuscarClick(Sender: TObject);
begin
SBtnNuevo.Enabled := BtnBuscarPulsadoCategorias;
SBtnEditar.Enabled := BtnBuscarPulsadoCategorias;
SBtnEliminar.Enabled := BtnBuscarPulsadoCategorias;
if not BtnBuscarPulsadoCategorias then
begin
EdBuscar.Enabled := True;
SBtnBuscar.Down := True;
SBtnOKBuscar.Enabled := True;
BtnBuscarPulsadoCategorias := True;
EdBuscar.SetFocus;
end
else
begin
EdBuscar.Text := '';
SBtnBuscar.Down := False;
EdBuscar.Enabled := False;
SBtnOKBuscar.Enabled := False;
BtnBuscarPulsadoCategorias := False;
end;
end;
Y para el botón OK escribimos el siguiente:
procedure TFrmAgenda.SBtnOKBuscarClick(Sender: TObject);
begin
if BtnBuscarPulsadoCategorias then
begin
if EdBuscar.Text = '' then
begin
ShowMessage('Debe escribir un texto para realizar la búsqueda');
EdBuscar.SetFocus;
end
else
begin
if TblCategorias.Locate('DESCRIPCION', EdBuscar.Text, [loCaseInsensitive,
loPartialKey]) then
DBGCategorias.SetFocus
else
ShowMessage('No se encuentra ninguna categoría con esa descripción');
SBtnBuscar.Down := False;
EdBuscar.Text := '';
EdBuscar.Enabled := False;
SBtnOKBuscar.Enabled := False;
BtnBuscarPulsadoCategorias := False;
SBtnNuevo.Enabled := True;
SBtnEditar.Enabled := True;
SBtnEliminar.Enabled := True;
end;
end;
end;
Con lo que ya tenemos funcionando toda la parte de definición de categorías para nuestra
agenda. En el capítulo siguiente, daremos cuerpo a la parte de contactos. Tened en cuenta que,
visto lo que hemos visto aquí con tanto detalle, me saltaré algunas partes dejándoos a vosotros
que penseis un poco y las desarrolleis. Vereis como no es tan difícil.
Ejercicio
Ampliar el programa no permitiendo repetir categorías. Sugerencia: usar un SELECT sobre la
tabla AUXILIAR con la función EXISTS de SQL.
A1. Borland Database Engine
En este apartado vamos a ver los aspectos más básicos que necesitaremos configurar para
poder acceder a nuestras bases de datos desde un programa Delphi. Arrancaremos el programa
de configuración de BDE accediendo a la ruta Panel de control -> BDE Administrator, con lo
que se nos abrirá la ventana:
A la izquierda, en la pestaña Databases tenemos una lista con todos los alias que hayamos dado
de alta. A la derecha no tenemos nada porque no hemos seleccionado alias alguno. Si pulsamos
sobre un alias cualquiera, la parte derecha cambia y se muestra la configuración del alias, que
podremos editar.
Vamos a comenzar creando un nuevo alias. Con este nuevo alias podremos hacer referencia a la
base de datos desde Delphi. Para ello, pulsamos en el menú Object, elegimos New... y a
continuación escogemos el tipo de base de datos de la lista que nos ofrece:
Trataremos con Interbase por ser un gestor que da suficiente potencia a la base de datos, así
como que es gratuito y con buena calidad. Para ello, elegimos como nombre de driver INTRBASE.
Hecho esto, veremos aparecer el nuevo alias, con un nombre temporal (a espera de que
nosotros pongamos el nuestro) y con un indicador de que es necesario aplicar los cambios para
dar la tarea por concluida:
A la derecha de la pantalla nos han aparecido las opciones por defecto para este nuevo alias:
Comenzaremos cambiando el nombre del alias, escribiendo DBPrueba en el lugar de INTRBASE1,
que es el que sugiere por defecto:
Ahora vamos a centrarnos en las opciones más importantes que nos ofrece:
BLOB SIZE
Tamaño máximo en Kb que podrá tener un campo de tipo Blob al insertarlo o
recuperarlo de la base de datos. Es recomendable que tenga un tamaño entre 32 y 1000
Kb
BLOBS TO CACHE
Es el número máximo de blobs que pueden estar almacenados a la vez en el ordenador
cliente. No es conveniente que sea una número muy grande. El valor suele variar entre
64 y 65536.
LANGDRIVER
Es el juego de caracteres usado por la base de datos. Es recomendable dejar en blanco
el campo.
MAX ROWS
Es el número de filas que devolverá la base de datos al hacer una consulta. Si dejamos
el valor -1 (recomendado), nos devolverá todas las filas que cumplan la condición de la
consulta.
OPEN MODE
Es el modo de apertura de la base de datos. Sólo hay dos posibles formas de abrirla:
READ ONLY
La base de datos se abre en modo lectura, con lo que no podremos
escribir registros ni actualizarlos
READ/WRITE
Es la opción por defecto. Teniendo esta opción, podremos realizar
cualquier tipo de operación sobre la base de datos
SERVER NAME
Nombre del servidor y ruta dentro del mismo vía el que se accede a la base de datos.
Depende de cómo esté configurado el acceso a la red, se escribirá de una de las
siguientes formas:
Acceso local
Unidad:\Ruta\Fichero.gdb
En red con TCP/IP bajo
Windows
NombreMaquina:Unidad:\Ruta\Fichero.gdb
En red con TCP/IP bajo
Unix
NombreMaquina:Ruta/Fichero.gdb
En red con NETBEUI
NombreServidor\\Unidad:\Ruta\Fichero.gdb
La extensión gdb es propia de los ficheros de Interbase.
USER NAME
Nombre de usuario que se tomará por defecto al establecer la conexión con el servidor.
Cuando instalamos Interbase hay un usuario administrador por defecto, que es SYSDBA.
Será recomendable usar un nuevo usuario. Si no queremos que el sistema nos muestre
el nombre del usuario cuando vayamos a establecer la conexión, lo dejaremos en blanco.
Esto no querrá decir que no haya un usuario definido, sólo que no se verá qué nombre
es.
Dejaremos todas las opciones por defecto para nuestro alias, salvo dos, SERVER NAME y USER
NAME. Usaremos una base de datos local, así que en SERVER NAME simplemente escribiremos la
ruta en la que se encuentra el fichero. Por otra parte, como nombre de usuario pondremos
Prueba. En el apartado de Interbase veremos cómo dar de alta usuarios.
, con lo que ya tenemos dado de alta el alias. A
Finalizamos pulsando el botón de "Aplicar"
partir de ahora podremos acceder a la base de datos desde Delphi simplemente refiriéndonos a
DBPrueba.
Si intentamos abrirla pulsando el + que hay al lado del nombre del alias, el programa nos dará
un error informándonos de que no puede acceder a la base de datos. Hemos creado el alias,
pero en ningún momento hemos creado físicamente la base de datos. En el capítulo de Interbase
veremos cómo hacerlo.
A2. InterBase
Vamos a crear una base de datos Interbase. Para ello, abriremos el programa IBConsole, que se
instala junto con Interbase. Si el servicio de Interbase no se carga de forma automática (en los
sistemas Windows NT y Windows 2000 se carga de forma automática), tendremos que
arrancarlo nosotros de forma manual.
Recién instalado el servidor de Interbase, al abrir el programa IBConsole no tendremos
definidos servidores ni más usuarios que el usuario por defecto, SYSDBA, cuya clave de acceso es
masterkey.
Sobre la opción InterBase Servers pulsaremos con el botón derecho del ratón, con lo que se
nos despliega el siguiente menú:
Elegimos Register... y accedemos a la pantalla que nos permite dar de alta el servidor local.
Hasta que no registremos un servidor local, no tendremos accesible la opción de dar de alta un
servidor remoto. En la pantalla que vemos:
rellenaremos los campos USER NAME y PASSWORD con los valores respectivos SYSDBA y masterkey
(muy importante que la clave esté en minúsculas). Pulsamos el botón OK y ya tenemos
registrado el servidor local, que será nuestra propia máquina. Ahora podemos crear bases de
datos en el servidor local, registrar bases de datos existentes (importante si queremos acceder a
ellas, pues sólo veremos las registradas) y registrar servidores remotos (uno o varios).
Comenzaremos viendo cómo crear un nuevo usuario. Cuando hemos registrado el servidor local,
el aspecto de la pantalla principal cambia un poco, mostrándonos estas opciones:
Si pulsamos sobre Users veremos únicamente al usuario SYSDBA. Para crear uno nuevo,
accedemos a la opción User security del menú Server. Se nos muestra entonces la ventana:
en la que pulsaremos el botón New, con lo que se vacían los campos USER NAME y PASSWORD para
que los rellenemos con los del nuevo usuario. Una vez introducidos los datos, pulsamos el botón
Apply, con lo que ya tenemos dado de alta el usuario.
Ahora vamos a crear la base de datos. Lo primero de todo será hacer login como el usuario que
queramos que tenga acceso a la base de datos, así que si estamos como SYSDBA y queremos
que el usuario sea PEPE, tendremos que "desregistrarnos" como SYSDBA y registrarnos como
PEPE en el servidor Local Server.
Estando en Local Server, subopción Databases, pulsamos el botón derecho y elegimos Create
database..., con lo que se nos abre la ventana:
Rellenamos el nombre del fichero (ruta completa) y el alias que le vamos a dar a la base de
datos, y pulsamos OK:
El directorio debe existir, o de lo contrario se nos mostrará un error de escritura. Creada la base
de datos, InterBase nos muestra la pantalla:
Ya podemos empezar a trastear con nuestra recién creada base de datos. Podemos crear tablas,
dar del alta registros, etc. Para ello, podemos emplear la utilidad ISQL, o bien SQL Explorer, del
propio Delphi, que es el que describimos brevemente en el anexo siguiente. Realmente, se
parecen tanto y son tan intuitivos, que no vale la pena repetir lo mismo.
No hay que olvidar que para poder acceder a la base de datos desde Delphi, tenemos que haber
creado un alias para ella, bien sea desde BDE Administrator o desde SQL Explorer. Crear un alias
desde InterBase no quiere decir que Delphi lo vaya a reconocer. Delphi sólo lo reconocerá si ha
sido creado desde sus herramientas.
A3. SQL Explorer
El programa SQL Explorer nos permite examinar bases de datos cuyo alias tengamos dado de
alta con mucha comodidad: separa los elementos de la base de datos en categorías: dominios,
tablas, generadores, funciones, procedimientos... Podremos modificar registros de las tablas sin
necesidad de acudir a sentencias SQL, simplemente situándonos sobre el campo a modificar,
actualizar valores de los generadores, editar procedimientos... y también nos permite introducir
sentencias SQL con las que podremos crear tablas, modificarlas, crear procedimientos,
generadores, etc. En última instancia, si se nos ha olvidado crear el alias a la base de datos con
el programa BDE Administrator, con SQL Explorer podremos hacerlo siguiendo exactamente los
mismos pasos.
Para mostrar el manejo básico de este programa, trabajaremos con un ejemplo muy sencillo (y
típico): supongamos que tenemos una librería, y únicamente necesitamos una base de datos
formada por una tabla con los siguientes datos:
•
•
•
•
•
•
•
•
Código Libro
Título
Autor
Tema
Editorial
Precio
Unidades
ISBN
Lo primero que tenemos que hacer es pensar de qué tipo de dato va a ser cada uno de los
campos de la tabla. Parece lógico pensar que los campos "Código Libro","Precio", "Unidades" van
a ser de tipo numérico, mientras que los demás serán de tipo carácter.
Ejecutamos el programa SQL Explorer, que viene con Delphi, para dar de alta el alias de esta
base de datos. En el anexo anterior vimos cómo crear la base de datos desde InterBase, así que
ahora ya podemos abrirla con SQL Explorer y crear tablas. Al ejecutarlo, se nos muestra la
siguiente pantalla:
Si pulsamos en el iconito del + que hay a la izquierda de nuestra base de datos:
se nos abre una ventana en la que tenemos que introducir el nombre de usuario y la contraseña
del usuario activo en Interbase cuando creamos la base de datos:
Entrados estos datos correctamente, se despliega una lista con varias entradas:
Además, también veremos que el botón izquierdo de abrir se ha pulsado automáticamente: la
base de datos está abierta, y podemos trabajar con ella. Podríamos haber conseguido lo mismo
poniéndonos sobre ella y pulsando ese botón. Luego la cerraremos con la opción CLOSE del menú
OBJECT, o bien "despulsando" el botón de abrir. Al abrirla, aparece en la ventana de la derecha
una nueva solapa: ENTER SQL. Podemos distinguir una base de datos abierta de una que no lo
está porque el icono que la acompaña está rodeada por un cuadrado de color verde, como se ve
en el dibujo. Si nos ponemos sobre ella, veremos esto:
Como hemos creado la base de datos, pero no le hemos añadido tablas, comprobamos pulsando
el icono + que esa entrada de la lista está vacía:
Así que la primera sentencia que vamos a introducir será la de la creación de la tabla. Para ello,
escribimos lo siguiente:
CREATE TABLE LIBROS(
CODIGO INTEGER NOT NULL,
TITULO VARCHAR(255) NOT NULL,
AUTOR VARCHAR(100),
TEMA VARCHAR(100),
EDITORIAL VARCHAR(50),
PRECIO INTEGER,
UNIDADES INTEGER,
ISBN VARCHAR(25),
PRIMARY KEY (CODIGO)
);
y pulsamos sobre el botón de ejecutar. Podemos ver que ahora Tables sí que contiene una
entrada: la tabla que acabamos de crear. Si nos ponemos sobre la propia tabla, nos aparecen
más opciones:
De aquí, la pestaña que más nos interesa en este momento es DATA. ENTER SQL ya la
conocemos, y TEXT únicamente nos muestra la definición de la tabla. Útil por si olvidamos de
qué tipo eran los campos. Si nos ponemos sobre DATA, nos aparece esto:
Aquí podemos dar valores a los campos directamente, sin necesidad de escribir sentencias SQL.
Además, en la parte superior derecha de la ventana ha salido una barra de botones que
explicamos a continuación casi completamente (únicamente nos dejaremos dos de ellos). Esta
barra de botones nos va a servir para movernos entre registros, añadir registros, borrar
registros, actualizarlos...
Sin embargo, como estamos aprendiendo, vamos a ver primero un ejemplo de inserción de un
registro con la instrucción INSERT de SQL. Para ello, empezamos por situarnos en la pestaña
ENTER SQL, e introducimos lo siguiente:
INSERT INTO LIBROS(
CODIGO, TITULO, AUTOR, TEMA, EDITORIAL, PRECIO, UNIDADES, ISBN
) VALUES (
1
, 'Manual de Matematicas'
, 'I. Bronshteim'
, 'Matematicas'
, 'Mir'
, 1500
, 10
, '5-38588-5'
);
como se puede ver en el gráfico:
Al pulsar sobre el botón de ejecutar la instrucción, veremos que en la barra de estado pone "1
rows were affected". Si nos vamos a la solapa DATA, aún no veremos nada: eso es porque no
hemos actualizado los datos. Vamos a explicar ahora para qué sirven los botones de la parte
superior derecha:
Así que tendremos que pulsar el botón de actualizar datos para poder ver el resultado de la
inserción:
Como no caben todos los datos, con ayuda de las barras de desplazamiento podremos ir
comprobando que los valores han sido introducidos correctamente.
Con todo esto, podemos seguir introduciendo datos para practicar con SQL, o directamente en la
solapa DATA. Además, podemos también investigar qué sucede con las sentencias UPDATE,
DELETE y SELECT. Como último ejemplo de este capítulo, vamos a ver el resultado de una
SELECT (previamente, he insertado dos registros más que podeis insertar a vuestro gusto como
ejercicio ;-) ). Escribimos lo siguiente:
SELECT * FROM LIBROS WHERE PRECIO > 1000;
Y al pulsar sobre el botón que ejecuta la instrucción, obtenemos:
Al desplazarnos hasta llegar al campo PRECIO:
observamos que los campos han sido devueltos correctamente.
Usar este programa para crear generadores, triggers, procedimientos, etc. es bastante sencillo.
Normalmente haremos todo este trabajo en la pestaña ENTER SQL. Además, cada elemento tiene
siempre la opción de desplegar datos sobre él. Por ejemplo, una tabla concreta despliega datos
sobre quién es la clave primaria, qué claves ajenas tiene o qué triggers se han definido sobre
ella (entre otros). Los procedimientos almacenados nos dirían cuáles son los parámetros de
entrada, las vistas sus columnas... Es un programa muy intuitivo y agradable de manejar, así
que el resto del aprendizaje os lo dejo a vosotros ;-)
Descargar