miércoles, noviembre 14, 2007

Usando SQL con Advantage de la manera fácil

Pasado el último incidente de ingrata memoria, lo mejor va a ser ponernos a trabajar nuevamente que para eso estamos aquí.

Durante las últimas 2 semanas después de mi regreso de Chile y Argentina, varios de mis usuarios de ADS me han estado preguntado sobre el uso de SQL para acceder a las tablas de datos DBF o ADTs, así que esto me ha motivado a escribir este artículo.

Una de las grandes carencias del lenguaje XBase es la capacidad de hacer queries (búsquedas) sobre una o varias tablas DBF extraer los resultados y mostarlos todos en una "vista", en XBase hay que hacer ese trabajo a mano, mediante índices, SET RELATION, SCOPES incluso SET FILTER y otras cosas mas. El resultado no siempre se obtiene de la manera mas rápida ni con la menor cantidad de tiempo invertida en la programación, si tuviéramos un SQL, la cosa resultaría mucho mas rápida.

Desafortunadamente el modelo XBase tal cual como lo conocemos ha sacrificado el modelo "relacional" por el modelo "navegacional", dando preferencia a mostrar las tablas en listados en vez de tratar de obtener la menor cantidad de información posible para mostrar en la pantalla, como lo hace SQL.

Si pudieramos tener el poder del modelo navegacional del XBase, de la mano del poder relacional del SQL, sobre nuestros veteranos archivos DBFs, pues otro gallo nos cantaría podríamos trabajar y obtener resultados en menos tiempo y realizar complejísimas búsquedas sobre uno o mas archivos DBF, relacionar sus campos y obtener un resultado rápido y ordenado de un criterio de búsqueda dado.

¿ La solución ?, ADS de la mano del RDDADS de xHarbour.

Lo que vamos a analizar a continuación está disponible tanto con el servidor local como con el servidor remoto de ADS, pero solo puede usarse con el RDDADS de (x)Harbour a 32 bits, lo siento chicos de Clipper, el cliente ADS para Clipper no soporta el uso de SQL. (En los próximos días publicaré un artículo para que todo el mundo le pierda el miedo a (x)Harbour, de la mano con una sorpresa por parte del Equipo Xailer).

Manos a la obra, ¿ qué necesitamos ?:

1) Un (x)Harbour cualquier versión
2) El RDDADS.LIB y el ACE32.LIB para linkear a nuestro EXE
3) Las DLLs del cliente ADS (ACE32.DLL, AXCWS32.DLL y ADSLOC32.DLL para el servidor local)
4) Un código fuente .PRG con las instrucciones correspondientes.

Modo de preparación:

Antes de meternos en el mundillo del SQL con ADS, tenemos que analizar un poco como es que funciona un motor de datos SQL.

En un sistema gestor de bases datos relacional, como MySQL, SQL Server, y el mismo ADS, el concepto de "BASE DE DATOS" cambia con respecto a lo que conocemos como "BASE DE DATOS" en el modelo XBase. Mientras que en el modelo XBase tradicional erroneamente le llamamos "base de datos" a UN archivo o tabla .DBF, en el modelo relacional una base de datos es una COLECCION de tablas, indices, usuarios, esquemas de seguridad, vistas, procesos almacenados, etc.

En todos los productos basados en SQL, es necesario realizar una CONEXION a la base de datos, esto se hace comúnmente mediante un Middleware como ODBC ó ADO y mediante una serie de instrucciones desde el lenguaje de programación que realizan la conexión primero con el servidor de base de datos y segundo con la propia base de datos, para tener acceso a los datos almacenados en sus tablas.

El modelo cambia un poco dentro de ADS, ya que ADS soporta 2 tipos de conexiones, lo que conocemos como TABLAS LIBRES, es decir archivos DBF o ADTs individuales que manipulamos usando nuestro lenguaje XBase tradicional, o bien un modelo de conexión mas aproximado a lo que es el modelo relacional, que es el modelo basado en DICCIONARIO DE DATOS.

Un DICCIONARIO DE DATOS para ADS es similar a un base de datos de un SQL, es decir, un DD (Diccionario de Datos) guarda referencia a las tablas DBF o ADT individuales, y al mismo tiempo guarda el esquema de seguridad de los usuarios, procesos almacenados, integridad referencial y todo lo que puedes esperar de un verdadero sistema gestor de base de datos relacional.

Usar DDs con ADS tiene grandes ventajas contra el modelo de tabla libre, como por ejemplo el poder mover la seguridad de la base de datos a ser controlada por propio servidor, en vez de tener que controlarla por programa, el evitarte tener que abrir todos las tablas individualmente una a una, ya que en el modelo tradicional XBase hay que hacer un "USE" por cada tabla que quieras usar, con un diccionario no, simplemente conectas desde tu programa con tu diccionario de datos, y listo, todas tus tablas están disponibles sin necesidad de tener que saber en que directorio las tienes, el DD se encarga de todo.

Pues bien, siguiendo el modelo relacional, para poder utilizar un querys con ADS, lo primero que tenemos que hacer es realizar una CONEXION con la base de datos, si tengo un diccionario de datos no tengo ningún problema, el RDDADS provee de la función ADSConnect60() que me permite "conectar" a un DD desde mi programa xHarbour....

¿ Pero que pasa si no tengo DD y estoy trabajando con tablas libres ?

No hay ningún problema ADS reconocerá como "base de datos" al contenedor de dichas tablas libres, y el "contendor" de las tablas libres es, simplemente la carpeta o directorio del disco duro donde se encuentran alojados los DBFs con sus NTX o CDX o bien los ADTs con sus respectivos ADIs.

¿ Cómo hacemos entonces para "conectar" con una carpeta del disco duro ?

El RDDADS de (x)Harbour provee de la función ADSConnect() mediante la cual podremos "conectarnos" con un directorio del disco duro, simplemente indicando la ruta donde se encuentran nuestros DBF o ADTs dentro del disco duro:

ADSConnect("C:\programas\datos\")

Si queremos saber si ya hay una conexión previamente establecida , utilizamos la función ADSConnection(), de tal forma que podríamos hacer algo como esto:

IF ADSConnection() == 0
ADSConnect("C:\programas\datos")
ENDIF

Si estas usando un DD, entonces, en vez de usar la función ADSConnection() vas a utilizar la función ADSConnect60():

ADSConnect60("C:\programas\datos\datadict.add",7,"usuario","password")

Ya "conectamos" con nuestra "base de datos" (directorio donde están los archivos o en su defecto DD que tiene la relación hacia las tablas que vamos a utilizar), ¿ que sigue ahora ?

El siguiente paso es igual tanto para tablas libres como para DDs y consiste en "preparar" la ejecución del query SQL, para ello vamos a utilizar la función ADSCreateSQLStatement() a la cual pasaremos 2 parametros: el primero es el nombre de un "alias" (si si, a lo Xbase, un alias) para el resultado del query (lo que en SQL se llama "cursor") y el segundo parámetro es el tipo de tabla sobre el cual estamos trabajando, siendo los valores válidos :

1 = DBFNTX,
2 = DBFCDX,
3 = ADTADI,

así que la preparación de nuestro query quedaría así:

ADSCreateSQLStatement("mialias",2) // 1= DBFNTX 2 = DBFCDX 3=ADTADI

Y ahora sí, podemos ejecutar el Query que nosotros queramos, de acuerdo a las instrucciones y funciones SQL soportadas por el motor SQL de ADS llamado Xtremeline SQL (ver mas adelante), esto lo haremos mediante la función ADSExecuteSQLDirect():

ADSExecuteSQLDirect("Select nombre, dire, tel from clientes order by nombre where nombre like '%Juan%'")

Ahora viene lo sorprendente: El resultado de este query ¡¡¡¡ SE COMPORTA EXACTAMENTE IGUAL QUE SI FUERA UN DBF !!!!!, de tal forma que tu podrías hacer algo como esto:

mialias->nombre := "Juan Pérez"
mialias->(DBGOTOP())
DO WHILE ! mialias->(EOF())
...
...
...
mialias->(DBSKIP())
ENDDO

¿ Y si quiero "browsear" el resultado de esto ?

Con xHarbour modo consola muy fácil:

mialias->(Browse())

y con Xailer, basta pegar el ALIAS a un objeto DBBrowse:

::oDBBrowse1:SetDBF("mialias")

En ninguno de los 2 casos necesitas cambiar los bloques de código que definen la navegación porque ADS "engaña" a xHarbour mediante el RDDADS, haciendole creer que lo que está visualizando es un DBF y no el resultado de un Query SQL ;-).

Cuando hallas terminado de utilizar este query, pues simplemente haces:

mialias->(DBCLOSEAREA())

Y listo, ya puedes ejecutar otro query de SQL.

El ejemplo completo para (x)Harbour en modo consola sería algo como esto:

Function Main
REQUEST ADS
RDDSETDEFAULT("ADS")

ADSSetFileType(2)
ADSSetServerType(7)

IF ADSConnection() == 0
ADSConnect("C:\programas\datos")
ENDIF

ADSCreateSQLStatement("mialias",2) // 1= DBFNTX 2 = DBFCDX 3=ADTADI

ADSExecuteSQLDirect("Select nombre, dire, tel from clientes order by nombre where nombre like '%Juan%'")

CLS

mialias->(DBGOTOP())
DO WHILE ! mialias->(EOF())
? mialias->nombre, mialias->dire, mialias->tel
mialias->(DBSKIP())
ENDDO

mialias->(DBGOTOP())
mialias->(BROWSE())

RETURN

Los queries pueden ser tan complejos como quieras, pudiendo incluso ejecutar procesos almacenados, puedes incluso realizar proceso "ciegos" como INSERT INTO, UPDATE o DELETE, solo que estas instrucciones no devolverán un cursor y por lo tanto no podrás visualizar nada del resultado de estas instrucciones SQL.

He creado un pequeño manual con las instrucciones SQL soportadas por el XtremeLine SQL de ADS junto con sus funciones, este manual lo he extraído de mi libro de Advantage Database Server y de lo puedes descargar haciendo click aqui.

Esta técnica de mezclar instrucciones Xbase con queries SQL es muy útil en tu programación, yo la utilizo especialmente cuando tengo necesidad de traer datos de distintas tablas, para evitarme archivos temporales.

11 comentarios:

Francis Reyna Avalos dijo...

Hola Master Antonio

Y ejemplos con FWH, seria posible...

Salu2 desde Peru - Iquitos

Francis

Rene Flores dijo...

Francis:

Por razones expuestas en este blog, hemos dejado de dar soporte a FiveWin.

Lamentamos las molestias que esto les ocasione

Carlos Sincuir dijo...

Rene, muy interesante tu artículo.

Pero yo me pregunto, porque usar SQL para atacar archivos dbfs?
Solo por el simple hecho de seguir trabajando con comando xBase?

Para mi, si se va a empezar a trabajar con SQL, y vamos a meternos en este nuevo mundo, por así decirlo, y aprender su lenguaje (INSERT, UPDATE, DELETE, DROP, etc), pues entonces mejor utilizar un motor de base de datos como tal, digase, SQL Server 2005, Oracle, DB2, etc. que son por así decirlo los grandes, pero que ahora ofrecen versiones Express, gratis para instalar a los clientes, con capacidades de 4 a 5Gb dependiendo el motor, o bien utilizar Firebird o PostgreSQL que son totalmente gratis, y con la ventaje de que todos los motores que menciono pueden instalarse en Windows o Linux, a excepción de SQL Server 2005 por supuesto.

Y como atacar estos motores con Harbour o xHarbour, independiente de la GUI, pues ya sea con puro ADO, que costaría bastante si no mucho, pero se puede o con Condor1 de Manu Exposito, que sería mucho mas fácil, ya sea con comandos xBase o con puro SQL que es lo que mas recomiendo.

Creo que con la llegada de Harbour/xHarbour y sus respectivas GUI's asociadas (FWH, Xailer, etc) los que venimos de Clipper ya podemos subir de nivel, y codearnos con los que supuestamente tienen herramientas de punta para atacar estos motores de bases de datos, sin sentirnos de menos.

Esta es mi forma de pensar, con respecto a utilizar el lenguaje SQL.

Saludos.

Carlos Sincuir.

José Murugosa dijo...

René
Tal vez esté un poco fuera de tema pero.. considerando tus comentarios vertidos sobre ADS, deseo repetir (como te lo manifesté en 2 mails) que desearía comparte a tí ADS con el correspondiente manual para usuarios de xHarbour y FWH y un curso que ofreces u ofrecías en tu página de Cyber Tec, desearía te comunicaras por favor conmigo a jmurugosa@gmail.com

Por cierto..... desapruebo absolutamente lo de Antonio, pero... que tenemos que ver nosotros quienes queremos utilizar ADS con FWH motivados por tí y que ahora.... ¿quedaremos sin soporte?

Por favor, quisiera saber tu posición sobre este asunto en un ámbito más privado, via mail.

BielSys dijo...

Muy interesante Rene, ademas me viene com anillo al dedo porque estoy apunto de empezar un proyecto con ADS.
Con referencia a las sentencias SQL y demas, si usamos DBF, el tema optimización de indices hace algo el motor, no hace nada, o solo hace si esta definido el diccionario de datos.
Igual es un poco chorra la pregunta, pero ya sebes, cosa de novatos.
Saludos
Biel

Rene Flores dijo...

Carlos:

No se trata de manejar DBF por capricho, mucha gente no utiliza ADS porque desconoce todo el potencial que hay detras de ADS como puede ser el encriptamiento de los datos, seguridad de la informacion (aun en formatos DBF), además de un completisimo motor cliente servidor que soporta lo que soporta cualquier motor CS tanto open source como de paga.

Te recomiendo que leas un articulo de este mismo blog que se llama "Porque usar ADS y no un SQL", hay muchas cosas detrás que el simple hecho de seguir manejando DBF.

José:

Contestado a tu correo privado el tema del ADS que deseas adquirir

Biel:

Si, los indices influyen mucho en desempeño de la base de datos, aun los indices bajo varias llaves. El desempeño de la aplicacion mejora enormemente por usar indices.

Y no, no necestias usar un diccionario para que ADS haga uso de los indices para optimizar queries.

Carlos Sincuir dijo...

Rene.

Yo no he dicho que sea capricho el seguir utilizando DBF’s, o que yo no conozca o haya utilizado ADS. Yo utilice ADS con varios y clientes y el mas grande tenía una red con 40 y 50 usuarios usando mi sistema que estaba en puro Clipper, instale el ADS con un servidor Novell y trabajo si problemas por un lapso de 6 años o mas, ya no me acuerdo, pero luego el cliente siguió creciendo, a casi el doble y te imagines el costo de seguir utilizando ADS. Por lo que migramos el sistema a Windows, instalando un servidor Linux + MySql, que resultó mas barato la licencia, para mas de 100 usuarios trabajando al mismo tiempo, local y remotamente. Para atacar al MySql utilice xHarbour, FWH y Eagle1 de Manu Exposito (que si no fuera por la ayuda de el y de su gran librería, no hubiera podido hacerlo).

Hace poco, este mismo sistema me lo solicitaron para que lo instalara en otra empresa pero trabajando con SQL Server 2005, y que cambié al código, mas que solo el objeto de conexión, utilizando Condor1, toda mi programación SQL me sirvió en casí un 99% entre MySQL y SQL Server 2005. Ahora tengo enlazado Eagle1 y Condor1 con mi sistema y puedo acceder a estos dos motores y a otros mas que estoy estudiando.

En otras palabras, lo que quería dar a conocer, es que ya contamos con una buena base para poder hacer una programación en 3 capas utilizando siempre nuestra base de desarrollo que es xHarbour + la GUI que queramos utilizar.
Capa de Datos ( Servidor )
Capa de Negocios ( Servidor de Negociación )
Capa de Presentación ( Cliente )

Xailer tiene ya una buena base para trabajar de esta forma con sus DataSources y DataSets, al igual que lo hace .NET u otros lenguajes.

A eso me refería de que si vamos a invertir tiempo en aprender el SQL, ya no nos quedemos solo con el lado de las DBF’s, hay otro mundo de posibilidades del otro lado, con varias opciones gratis y muy poderosas.

Yo estoy ahora en la tarea de ver las diferencias entre la estructura que utilizan MySql, SQL Server 2005 (con su Transac SQL), Oracle, DB2, PostgreSQL y Firebird, que son los motores que quiero hacer compatible mi sistema, para que cualquier cliente pequeño, mediano o grande utilice el que mas le parezca, sin tener que hacer muchos cambios o ninguno, en mi capa de cliente y regla de negocios, solamente en la capa del servidor.


Saludos.

Carlos Sincuir

Anónimo dijo...

y de donde puedo obtener o bajar lo que necesito por la parte de ADS (ace32.dll, AXCWS32.DLL, ADSLOC32.DLL)?

Gracias de Antemano.

Salu2,
Guillermo Varona

Daniel dijo...

Puede ser que si tengo abiertas DBF usando USE, la funcion ADSCreateSQLStatement me devuelva .F. ?

jmcastro dijo...

Quisiera que alguien me ayude con algun ejemplo para accesar archivos DBF con indices CDX desde un script PHP haciendo uso de ADS.-
Tengo instalado ADS en Ubuntu 9.10, ademas de APACHE2 y PHP5.-
No encontre doc de como debo hacer uso desde PHP.-

Desde ya muchas gracias.-

MTR dijo...

Muchas Gracias Rene, lo he encontrado muy útil.. saludos desde Colombia