SET RELATION es uno de los comandos mas poderosos del XBASE pero la gente se complica mucho la vida usandolo, o definitivamente no lo usa.
En realidad no tiene nada de complicado, y es super poderoso, porque te permite "sincronizar" bases de datos, es excelente para cuando tienes campos relacionados y te interesa que las tablas dbf se "dejen huellas" entre si y no quieres hacer un SELECT para buscar en otra area
Funciona de la siguiente manera.
En este ejemplo vamos a relacionar 3 tablas "hijas" contra una tabla "padre" asumimos que por cada registro en la tabla padre, existe uno o mas registros correspondientes en las tablas hijas.
1) Se abren primero las tablas "hijas", estas tablas es conveniente que esten indexadas en base al campo sobre el cual se establece la relacion.
- Code: Select all Expand view RUN
USE pv.dbf shared new
pv->(ORDSETFOCUS("pvcode"))
pv->(DBGOTOP())
USE groups.dbf shared new
groups->(ORDSETFOCUS("groucode"))
groups->(DBGOTOP())
USE channel.dbf SHARED NEW
channel->(ORDSETFOCUS("chancode"))
channel->(DBGOTOP())
Es muy importante, aunque no necesario, que el campo que relaciona las tablas se llame IGUAL en todas la tablas y sea del mismo tipo, mismo tamaño y mismo numero de decimales en caso de ser un campo numerico.
2) Como seguno paso. Se abre la base de datos "padre", y se indexa por cualquier criterio.
USE agents.dbf SHARED NEW
agents->(ORDSETFOCUS("IATA"))
3) y ahora viene la magia, vamos a relacionar campos de la tabla padre, con sus correspondientes en las tablas hijas:
- Code: Select all Expand view RUN
SET RELATION TO channelcod INTO channel ADDITIVE
SET RELATION TO groupcode INTO group ADDITIVE
SET RELATION TO pvcode INTO pv ADDITIVE
(cAliasAgents)->(DBGOTOP())
El comando SET RELATION recibe como clausulas EL NOMBRE DEL CAMPO DENTRO DE LA TABLA PADRE (channelcod, groupcode y pvcode) el INTO establece el ALIAS de la tabla hija. ¿ Como sabe la relacion contra que campo en tabla hija se asocia el padre ?, muy facil, la tabla hija tiene un campo CON EL MISMO NOMBRE que el campo en la tabla padre, es decir, que si en la tabla padre existe un campo llamado channelcod, en la tabla channel tambien existe un campo con el mismo nombre y preferentemente con las mismas características, como mencione anteriormente, no es necesario que el campo este indexado en la tabla hija, pero si es deseable porque esto acelera mucho el acceso a los datos cuando estamos trabajando con relaciones.
Finalmente la clausula ADDITIVE sirve para añadir nuevas relaciones al area padre, si no pones la clausula ADDITIVE, cada nueva relacion que añadas destruye a la anterior, poniendo ADDITIVE, eso no pasa.
3) El acceso a los datos es super mega facil, si estoy en la base de datos padre, y quiero saber el nombre de un campo hago:
agents->nombre
Y si quiero saber el valor del campo nombre, pero que esta en la base de datos hija channel, simplemente pregunto por el campo, indicando el alias de la tabla hija:
channel->nombre
Si yo muevo el puntero en la base de datos padre, AUTOMATICAMENTE todos lo punteros de TODAS las bases de datos hijas se mueven para reflejar la relacion correspondiente
4) ¿ que pasa si no existe un registro relacionado en la base de datos hija ?, no pasa nada, simplmente se devuelve un campo vacio (en realidad el puntero de la base de datos hija esta apuntando a EOF).
Bien, pero que pasa si quiero en un browse tener columnas que vienen de disintas tablas, sin tener que ir a buscarlas, ni tener que hacer un archivo temporal (es decir, matar pulgas a cañonazos) .... jejeje, pues es muy facil.
Si ya tengo relacionadas las tablas pues basta con definir el browse asi:
REDEFINE LISTBOX oBrw FIELDS agents->nombre, channel->nombre, pv->precio ID .......
las columnas relacionadas cambian automaticamente cuando te mueves sobre el browse.
5) ¿ Que pasa si en la tabla hija, hay mas de un registro que coincide con el registro relacionado en tabla padre? por ejemplo en un maestro detalle, donde solo hay un registro padre, y varios registros hijos, por ejemplo de una factura.
Bien, la relacion apuntara AL PRIMER elemento de la tabla hija, luego entonces buscar los registros hijos, no tiene mucha complicacion.
Una de las cosas que poca gente sabe, e ignoro si esta soportada en (x)Harbour y que tenia Clipper 5.3, es la clausula SCOPED dentro del SET RELATION, la clausula SCOPED establece un SCOPE automatico en la tabla hija, filtrando los registros cada vez que te mueves en la tabla padre.
6) las relaciones se pueden anidar, porque a su vez, las tablas hijas, pueden ser a su vez, tablas padres y asi sucesivamente, es decir, podemos tener una tabla padre, una hija, una nieta, una bisnieta, etc, etc. etc.
Para acceder a los datos de la tabla nieta, entonces hacemos
aliastablahija->aliastablanieta->campoentablanieta
Si te mueves en la tabla padre, la tabla hija se mueve, y obviamente el puntero de la tabla nieta, tambien se mueve.
Como verán, mas facil, no se puede y ahorra miles de lineas de codigo.