2-5: Manejando SQL (I)
ShAd0w5
shadow5@0ri0n.org
Por fin la "sombra" se aparecio en el E-zine del grupo 0ri0n, aqui estoy con un articulo interesante e importante para nosotros amantes a la computadora y por supuesto para nuestra necesidad.
El lenguaje de consulta estructurado (SQL) es un lenguaje de base de datos normalizado, en este caso utilizaremos ejemplos para el motor de base de datos de Microsoft Jet >:-(. SQL se utiliza para crear objetos y llevar un mejor control en una Base de Datos.
En este capitulo vamos a empezar a conocer los fundamentos basicos del SQL como tambien los comandos, componentes, clausulas, operadores logicos, etc.
Tambien se puede utilizar con el metodo Execute para crear y manipular directamente las bases de datos Jet y crear consultas SQL de paso a traves para manipular bases de datos remotas cliente - servidor.
1.1- Componentes del SQL
El lenguaje SQL esta compuesto por comandos, clausulas, operadores y funciones de agregado. Estos elementos se combinan en las instrucciones para crear, actualizar y manipular las bases de datos.
1.2- Comandos
Existen dos tipos de comandos SQL:
los DLL que permiten crear y definir nuevas bases de datos, campos e indices. los DML que permiten generar consultas para ordenar, filtrar y extraer datos de la base de datos.
Comandos DLL
- CREATE: Utilizado para crear nuevas tablas, campos e indices.
- DROP : Empleado para eliminar tablas e indices.
- ALTER : Utilizado para modificar las tablas agregando campos o cambiando la definicion de los campos.
Comandos DML
- SELECT: Utilizado para consultar registros de la base de datos que satisfagan un criterio determinado.
- INSERT- Utilizado para cargar lotes de datos en la base de datos en una unica operacion.
- UPDATE - Utilizado para modificar los valores de los campos y registros especificados.
- DELETE - Utilizado para eliminar registros de una tabla de una base de datos.
1.3 Clausulas
Las clausulas son condiciones de modificacion utilizadas para definir los datos que desea seleccionar o manipular.
Clausulas
- FROM : Utilizada para especificar la tabla de la cual se van a seleccionar los registros.
- WHERE : Utilizada para especificar las condiciones que deben reunir los registros que se van a seleccionar.
- GROUP BY : Utilizada para separar los registros seleccionados en grupos especificos.
- HAVING : Utilizada para expresar la condicion que debe satisfacer cada grupo.
- ORDER BY : Utilizada para ordenar los registros seleccionados de acuerdo con un orden especifico.
1.4 Operadores Logicos
Operador
- AND : Es el "y" logico. Evalua dos condiciones y devuelve un valor de verdad solo si ambas son ciertas.
- OR : Es el "o" logico. Evalua dos condiciones y devuelve un valor de verdar si alguna de las dos es cierta.
- NOT : Negacion logica. Devuelve el valor contrario de la expresion.
1.5 Operadores de Comparacion
Operadores
- < Menor que
- > Mayor que
- <> Distinto de
- <= Menor o Igual que
- >= Mayor o Igual que
- = Igual que
BETWEEN : Utilizado para especificar un intervalo de valores.
LIKE : Utilizado en la comparacion de un modelo.
In : Utilizado para especificar registros de una base de datos.
1.6 Funciones de Agregado
Las funciones de agregado se usan dentro de una clausula SELECT en grupos de registros para devolver un unico valor que se aplica a un grupo de registros.
Funcion
- AVG : Utilizada para calcular el promedio de los valores de un campo determinado.
- COUNT : Utilizada para devolver el numero de registros de la seleccion
- SUM : Utilizada para devolver la suma de todos los valores de un campo determinado.
- MAX : Utilizada para devolver el valor mas alto de un campo especificado.
- MIN : Utilizada para devolver el valor mas bajo de un campo especificado.
2.- Consultas de Seleccion
Las consultas de seleccion se utilizan para indicar al motor de datos que devuelva informacion de las bases de datos, esta informacion es devuelta en forma de conjunto de registros que se pueden almacenar en un objeto recordset.
Este conjunto de registros es modificable.
2.1.- Consultas basicas
La sintaxis basica de una consulta de seleccion es la siguiente:
SELECT Campos FROM Tabla;
En donde campos es la lista de campos que se deseen recuperar y tabla es el origen de los mismos, por ejemplo:
SELECT Nombre, Telefono FROM Clientes;
Esta consulta devuelve un recordset con el campo nombre y telefono de la tabla clientes.
2.2.- Ordenar los registros
Adicionalmente se puede especificar el orden en que se desean recuperar los registros de las tablas mediante la clausula ORDER BY Lista de Campos. En donde Lista de campos representa los campos a ordenar. Ejemplo:
SELECT CodigoPostal, Nombre, Telefono FROM Clientes ORDER BY Nombre;
Esta consulta devuelve los campos CodigoPostal, Nombre, Telefono de la tabla Clientes ordenados por el campo Nombre.
Se pueden ordenar los registros por mas de un campo, como por ejemplo:
SELECT CodigoPostal, Nombre, Telefono FROM Clientes ORDER BY CodigoPostal, Nombre;
Incluso se puede especificar el orden de los registros: ascendente mediante la clausula (ASC -se toma este valor por defecto) o descendente (DESC)
SELECT CodigoPostal, Nombre, Telefono FROM Clientes ORDER BY CodigoPostal DESC , Nombre ASC;
2.3.- Consultas con Predicado
El predicado se incluye entre la clausula y el primer nombre del campo a recuperar, los posibles predicados son:
Predicado
- ALL : Devuelve todos los campos de la tabla.
- TOP : Devuelve un determinado numero de registros de la tabla.
- DISTINCT : Omite los registros cuyos campos seleccionados coincidan. totalmente.
- DISTINCTROW: Omite los registros duplicados basandose en la totalidad del registro y no solo en los campos seleccionados.
ALL
Si no se incluye ninguno de los predicados se asume ALL. El Motor de base de datos selecciona todos los registros que cumplen las condiciones de la instruccion SQL. No se conveniente abusar de este predicado ya que obligamos al motor de la base de datos a analizar la estructura de la tabla para averiguar los campos que contiene, es mucho mas rapido indicar el listado de campos deseados.
SELECT ALL FROM Empleados;
SELECT * FROM Empleados;
TOP
Devuelve un cierto numero de registros que entran entre al principio o al final de un rango especificado por una clausula ORDER BY. Supongamos que queremos recuperar los nombres de los 25 primeros estudiantes del curso 1994:
SELECT TOP 25 Nombre, Apellido FROM Estudiantes
ORDER BY Nota DESC;
Si no se incluye la clausula ORDER BY, la consulta devolvera un conjunto arbitrario de 25 registros de la tabla Estudiantes. El predicado TOP no elige entre valores iguales. En el ejemplo anterior, si la nota media numero 25 y la 26 son iguales, la consulta devolvera 26 registros. Se puede utilizar la palabra reservada PERCENT para devolver un cierto porcentaje de registros que caen al principio o al final de un rango especificado por la clausula ORDER BY.
Supongamos que en lugar de los 25 primeros estudiantes deseamos el 10 por ciento del curso:
SELECT TOP 10 PERCENT Nombre, Apellido FROM Estudiantes ORDER BY Nota DESC;
El valor que va a continuacion de TOP debe ser un Integer sin signo. TOP no afecta a la posible actualizacion de la consulta.
DISTINCT
Omite los registros que contienen datos duplicados en los campos seleccionados.
Para que los valores de cada campo listado en la instruccion SELECT se incluyan en la consulta deben ser unicos.
Por ejemplo, varios empleados listados en la tabla Empleados pueden tener el mismo apellido. Si dos registros contienen Lopez en el campo Apellido, la siguiente instruccion SQL devuelve un unico registro:
SELECT DISTINCT Apellido FROM Empleados;
Con otras palabras el predicado DISTINCT devuelve aquellos registros cuyos campos indicados en la clausula SELECT posean un contenido diferente. El resultado de una consulta que utiliza DISTINCT no es actualizable y no refleja los cambios subsiguientes realizados por otros usuarios.
DISTINCTROW
Devuelve los registros diferentes de una tabla; a diferencia del predicado anterior que solo se fijaba en el contenido de los campos seleccionados, Este lo hace en el contenido del registro completo independientemente de los campo indicados en la clausula SELECT.
SELECT DISTINCTROW Apellido FROM Empleados;
Si la tabla empleados contiene dos registros: Antonio Lopez y Marta Lopez el ejemplo del predicado DISTINCT devuleve un unico registro con el valor Lopez en el campo Apellido ya que busca no duplicados en dicho campo. Este ultimo ejemplo devuelve dos registros con el valor Lopez en el apellido ya que se buscan no duplicados en el registro completo.
2.4.- Alias
En determinadas circunstancias es necesario asignar un nombre a alguna columna determinada de un conjunto devuelto, otras veces por simple capricho o por otras circunstancias. Para resolver todas ellas tenemos la palabra reservada AS que se encarga de asignar el nombre que deseamos a la columna deseada. Tomado como referencia el ejemplo anterior podemos hacer que la columna devuelta por la consulta, en lugar de llamarse apellido (igual que el campo devuelto) se llame Empleado. En este caso procederiamos de la siguiente forma:
SELECT DISTINCTROW Apellido AS Empleado FROM Empleados;
2.5.- Recuperar Informacion de una base de Datos Externa
Para concluir este capitulo se debe hacer referencia a la recuperacion de registros de bases de datos externa. Es ocasiones es necesario la recuperacion de informacion que se encuentra contenida en una tabla que no se encuentra en la base de datos que ejecutara la consulta o que en ese momento no se encuentra abierta, esta situacion la podemos salvar con la palabra reservada IN de la siguiente forma:
SELECT DISTINCTROW Apellido AS Empleado FROM Empleados
IN 'RUTA';
En donde RUTA es la direccion donde esta la base de datos que contiene la tabla Empleados.
3.- Criterios de Seleccion
Hay que recalcar tres detalles de vital importancia. El primero de ellos es que cada vez que se desee establecer una condicion referida a un campo de texto la condicion de busqueda debe ir encerrada entre comillas simples; la segunda es que no se posible establecer condiciones de busqueda en los campos memo y; la tercera y ultima hace referencia a las fechas. Las fechas se deben escribir siempre en formato mm-dd-aa en donde mm representa el mes, dd el dia y aa el año, hay que prestar atencion a los separadores - no sirve la separacion habitual de la barra (/), hay que utilizar el guion (-) y ademas la fecha debe ir encerrada entre almohadillas (#). Por ejemplo si deseamos referirnos al dia 31 de Diciembre de 2001 deberemos hacerlo de la siguente forma; #12-31-01#
3.1.- Operadores Logicos
Los operadores logicos soportados por SQL son: AND, OR, XOR, Eqv, Imp, Is y Not. A excepcion de los dos ultimos todos poseen la siguiente sintaxis:
<expresion1> operador <expresion2>
En donde expresion1 y expresion2 son las condiciones a evaluar, el resultado de la operacion varia en funcion del operador logico. La tabla adjunta muestra los diferentes posibles resultados:
-------------------------------------------------------
| <expresion1> | Operador | <expresion2> | Resultado |
-------------------------------------------------------
| Verdadero | AND | Falso | Falso |
| Verdadero | AND | Verdadero | Verdadero |
| Falso | AND | Verdadero | Falso |
| Falso | AND | Falso | Falso |
| Verdadero | OR | Falso | Verdadero |
| Verdadero | OR | Verdadero | Verdadero |
| Falso | OR | Verdadero | Verdadero |
| Falso | OR | Falso | Falso |
| Verdadero | XOR | Verdadero | Falso |
| Verdadero | XOR | Falso | Verdadero |
| Falso | XOR | Verdadero | Verdadero |
| Falso | XOR | Falso | Falso |
| Verdadero | Eqv | Verdadero | Verdadero |
| Verdadero | Eqv | Falso | Falso |
| Falso | Eqv | Verdadero | Falso |
| Falso | Eqv | Falso | Verdadero |
| Verdadero | Imp | Verdadero | Verdadero |
| Verdadero | Imp | Falso | Falso |
| Verdadero | Imp | Null | Null |
| Falso | Imp | Verdadero | Verdadero |
| Falso | Imp | Falso | Verdadero |
| Falso | Imp | Null | Verdadero |
| Null | Imp | Verdadero | Verdadero |
| Null | Imp | Falso | Null |
| Null | Imp | Null | Null |
-------------------------------------------------------
Si a cualquiera de las anteriores condiciones le anteponemos el operador NOT el resultado de la operacion sera el contrario al devuelto sin el operador NOT. El ultimo operador denominado Is se emplea para comparar dos variables de tipo objeto <Objeto1> Is <Objeto2>. Este operador devuelve Verdadero si los dos objetos son iguales
SELECT * FROM Empleados WHERE Edad > 25 AND Edad < 50;
SELECT * FROM Empleados WHERE (Edad > 25 AND Edad < 50) OR Sueldo = 100;
SELECT * FROM Empleados WHERE NOT Estado = 'Soltero';
SELECT * FROM Empleados WHERE (Sueldo > 100 AND Sueldo < 500) OR
(Provincia = 'Merida' AND Estado = 'Casado');
3.2.- Intervalos de Valores
Para indicar que deseamos recuperar los registros segun el intervalo de valores de un campo emplearemos el operador Between cuya sintaxis es:
campo [Not] Between valor1 And valor2 (la condicion Not es opcional)
En este caso la consulta devolveria los registros que contengan en "campo" un valor incluido en el intervalo valor1, valor2 (ambos inclusive). Si anteponemos la condicion Not devolvera aquellos valores no incluidos en el intervalo.
SELECT * FROM Pedidos WHERE CodPostal Between 28000 And 28999;
(Devuelve los pedidos realizados en la provincia de Merida)
SELECT IIf(CodPostal Between 28000 And 28999, 'Provincial', 'Nacional')
FROM Editores;
(Devuelve el valor 'Provincial' si el codigo postal se encuentra en el intervalo, 'Nacional' en caso contrario)
3.3.- El Operador Like
Se utiliza para comparar una expresion de cadena con un modelo en una expresion SQL. Su sintaxis es:
expresion Like modelo
En donde expresion es una cadena modelo o campo contra el que se compara expresion. Se puede utilizar el operador Like para encontrar valores en los campos que coincidan con el modelo especificado. Por modelo puede especificar un valor completo (Pedro Zue), o se pueden utilizar caracteres comodin como los reconocidos por el sistema operativo para encontrar un rango de valores (Like An*).
El operador Like se puede utilizar en una expresion para comparar un valor de un campo con una expresion de cadena. Por ejemplo, si introduce Like C* en una consulta SQL, la consulta devuelve todos los valores de campo que comiencen por la letra C. En una consulta con parametros, puede hacer que el usuario escriba el modelo que se va a utilizar.
El ejemplo siguiente devuelve los datos que comienzan con la letra P seguido de cualquier letra entre A y F y de tres digitos:
Like 'P[A-F]###'
Este ejemplo devuelve los campos cuyo contenido empiece con una letra de la A a la D seguidas de cualquier cadena.
Like '[A-D]*'
En la tabla siguiente se muestra como utilizar el operador Like para comprobar expresiones con diferentes modelos.
--------------------------------------------------------------------------
| Tipo de coincidencia | Mod. Plan. | Coincide | No coincide |
--------------------------------------------------------------------------
| Varios caracteres | 'a*a' | 'aa', 'aBa', 'aBBBa'| 'aBC' |
| Caracter especial | 'a[*]a' | 'a*a' | 'aaa' |
| Varios caracteres | 'ab*' | 'abcdefg', 'abc' | 'cab', 'aab' |
| Un solo caracter | 'a?a' | 'aaa', 'a3a', 'aBa' | 'aBBBa' |
| Un solo digito | 'a#a' | 'a0a', 'a1a','a2a'' | aaa', 'a10a' |
| Rango de caracteres | '[a-z]' | 'f', 'p', 'j' | '2', '&' |
| Fuera de un rango | '[!a-z]' | '9', '&', '%' | 'b', 'a' |
| Distinto de un digito| '[!0-9]' | 'A', 'a', '&', 'ñ' | '0', '1', '9'|
| Combinada | 'a[!b-m]#'| 'An9', 'az0', 'a99' | 'abc', 'aj0' |
--------------------------------------------------------------------------
Donde Mod. Plan es Modo de Planteamiento.
3.4.- El Operador In
Este operador devuelve aquellos registros cuyo campo indicado coincide con alguno de los en una lista. Su sintaxis es:
expresion [Not] In(valor1, valor2, . . .)
SELECT * FROM Pedidos WHERE Ciudades In ('Caracas', 'Maracay', 'Merida');
3.5.- La clausula WHERE
La clausula WHERE puede usarse para determinar que registros de las tablas enumeradas en la clausula FROM apareceran en los resultados de la instruccion SELECT. Depues de escribir esta clausula se deben especificar las condiciones expuestas en los partados 3.1 y 3.2. Si no se emplea esta clausula, la consulta devolvera todas las filas de la tabla. WHERE es opcional, pero cuando aparece debe ir a continuacion de FROM.
SELECT Apellidos, Salario FROM Empleados WHERE Salario > 21000;
SELECT Id_Producto, Existencias FROM Productos
WHERE Existencias <= Nuevo_Pedido;
SELECT * FROM Pedidos WHERE Fecha_Envio = #5/10/01#;
SELECT Apellidos, Nombre FROM Empleados WHERE Apellidos = 'King';
SELECT Apellidos, Nombre FROM Empleados WHERE Apellidos Like 'S*';
SELECT Apellidos, Salario FROM Empleados WHERE Salario Between 200 And 300;
SELECT Apellidos, Salario FROM Empl WHERE Apellidos Between 'Lon' And 'Tol';
SELECT Id_Pedido, Fecha_Pedido FROM Pedidos WHERE Fecha_Pedido
Between #1-1-01# And #30-6-01#;
SELECT Apellidos, Nombre, Ciudad FROM Empleados WHERE Ciudad
In ('Sevilla', 'Los Angeles', 'Barcelona');
4.- Agrupamiento de Registros
4.1.- GROUP BY
Combina los registros con valores identicos, en la lista de campos especificados, en un unico registro. Para cada registro se crea un valor sumario si se incluye una funcion SQL agregada, como por ejemplo Sum o Count, en la instruccion SELECT. Su sintaxis es:
SELECT campos FROM tabla WHERE criterio GROUP BY campos del grupo
GROUP BY es opcional. Los valores de resumen se omiten si no existe una funcion.
SQL agregada en la instruccion SELECT. Los valores Null en los campos GROUP BY se agrupan y no se omiten. No obstante, los valores Null no se evaluan en ninguna de las funciones SQL agregadas.
Se utiliza la clausula WHERE para excluir aquellas filas que no desea agrupar, y la clausula HAVING para filtrar los registros una vez agrupados. A menos que contenga un dato Memo u Objeto OLE , un campo de la lista de campos GROUP BY puede referirse a cualquier campo de las tablas que aparecen en la clausula FROM, incluso si el campo no esta incluido en la instruccion SELECT, siempre y cuando la instruccion SELECT incluya al menos una funcion SQL agregada.
Todos los campos de la lista de campos de SELECT deben o bien incluirse en la clausula GROUP BY o como argumentos de una funcion SQL agregada.
SELECT Id_Familia, Sum(Stock) FROM Productos GROUP BY Id_Familia;
Una vez que GROUP BY ha combinado los registros, HAVING muestra cualquier registro agrupado por la clausula GROUP BY que satisfaga las condiciones de la clausula HAVING.
HAVING es similar a WHERE, determina que registros se seleccionan. Una vez que los registros se han agrupado utilizando GROUP BY, HAVING determina cuales de ellos se van a mostrar.
SELECT Id_Familia Sum(Stock) FROM Productos GROUP BY Id_Familia HAVING Sum(Stock) > 100 AND NombreProducto Like BOS*;
4.2.- AVG
Calcula la media aritmetica de un conjunto de valores contenidos en un campo especificado de una consulta. Su sintaxis es la siguiente:
Avg(expr)
En donde expr representa el campo que contiene los datos numericos para los que se desea calcular la media o una expresion que realiza un calculo utilizando los datos de dicho campo. La media calculada por Avg es la media aritmetica (la suma de los valores dividido por el numero de valores). La funcion Avg no incluye ningun campo Null en el calculo.
SELECT Avg(Gastos) AS Promedio FROM Pedidos WHERE Gastos > 100;
4.3.- Count
Calcula el numero de registros devueltos por una consulta. Su sintaxis es la siguiente :
Count(expr)
En donde expr contiene el nombre del campo que desea contar. Los operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una funcion (la cual puede ser intrinseca o definida por el usuario pero no otras de las funciones agregadas de SQL). Puede contar cualquier tipo de datos incluso texto.
Aunque expr puede realizar un calculo sobre un campo, Count simplemente cuenta el numero de registros sin tener en cuenta que valores se almacenan en los registros. La funcion Count no cuenta los registros que tienen campos null a menos que expr sea el caracter comodin asterisco (*). Si utiliza un asterisco, Count calcula el numero total de registros, incluyendo aquellos que contienen campos null. Count(*) es considerablemente mas rapida que Count(Campo). No se debe poner el asterisco entre dobles comillas ('*').
SELECT Count(*) AS Total FROM Pedidos;
Si expr identifica a multiples campos, la funcion Count cuenta un registro solo si al menos uno de los campos no es Null. Si todos los campos especificados son Null, no se cuenta e l registro. Hay que separar los nombres de los campos con ampersand (&).
SELECT Count(FechaEnvio & Transporte) AS Total FROM Pedidos;
4.4.- Max, Min
Devuelven el minimo o el maximo de un conjunto de valores contenidos en un campo especifico de una consulta. Su sintaxis es:
Min(expr)
Max(expr)
En donde expr es el campo sobre el que se desea realizar el calculo. Expr pueden incluir el nombre de un campo de una tabla, una constante o una funcion (la cual puede ser intrinseca o definida por el usuario pero no otras de las funciones agregadas de SQL).
SELECT Min(Gastos) AS ElMin FROM Pedidos WHERE Pais = 'Venezuela';
SELECT Max(Gastos) AS ElMax FROM Pedidos WHERE Pais = 'Venezuela';
4.5.- StDev, StDevP
Devuelve estimaciones de la desviacion estandar para la poblacion (el total de los registros de la tabla) o una muestra de la poblacion representada (muestra aleatoria). Su sintaxis es:
StDev(expr)
StDevP(expr)
En donde expr representa el nombre del campo que contiene los datos que desean evaluarse o una expresion que realiza un calculo utilizando los datos de dichos campos. Los operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una funcion (la cual puede ser intrinseca o definida por el usuario pero no otras de las funciones agregadas de SQL) StDevP evalua una poblacion, y StDev evalua una muestra de la poblacion. Si la consulta contiene menos de dos registros (o ningun registro para StDevP), estas funciones devuelven un valor Null (el cual indica que la desviacion estandar no puede calcularse).
SELECT StDev(Gastos) AS Desviacion FROM Pedidos WHERE Pais = 'Venezuela';
SELECT StDevP(Gastos) AS Desviacion FROM Pedidos WHERE Pais= 'Venezuela';
4.6.- Sum
Devuelve la suma del conjunto de valores contenido en un campo especifico de una consulta. Su sintaxis es:
Sum(expr)
En donde expr respresenta el nombre del campo que contiene los datos que desean sumarse o una expresion que realiza un calculo utilizando los datos de dichos campos. Los operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una funcion (la cual puede ser intrinseca o definida por el usuario pero no otras de las funciones agregadas de SQL).
SELECT Sum(PrecioUnidad * Cantidad) AS Total FROM DetallePedido;
4.7.- Var, VarP
Devuelve una estimacion de la varianza de una poblacion (sobre el total de los registros) o una muestra de la poblacion (muestra aleatoria de registros) sobre los valores de un campo. Su sintaxis es:
Var(expr)
VarP(expr)
VarP evalua una poblacion, y Var evalua una muestra de la poblacion. Expr el nombre del campo que contiene los datos que desean evaluarse o una expresion que realiza un calculo utilizando los datos de dichos campos. Los operandos de expr pueden incluir el nombre de un campo de una tabla, una constante o una funcion (la cual puede ser intrinseca o definida por el usuario pero no otras de las funciones agregadas de SQL).
Si la consulta contiene menos de dos registros, Var y VarP devuelven Null (esto indica que la varianza no puede calcularse). Puede utilizar Var y VarP en una expresion de consulta o en una Instruccion SQL.
SELECT Var(Gastos) AS Varianza FROM Pedidos WHERE Pais = 'Venezuela';
SELECT VarP(Gastos) AS Varianza FROM Pedidos WHERE Pais = 'Venezuela';
Bueno nos vemos para la proxima entrega del E-zine #3, espero que le haya gustado y por supuesto el resto de la revista. bye Happy Hacking.
--ShAd0w5 (shadow5@0ri0n.org)