Algo más sobre los conjuntos de caracteres

2 comentarios

Lo básico sobre los conjuntos de caracteres ya habíamos visto en este artículo:

Entendiendo a los conjuntos de caracteres

Y ahora haremos un repaso sobre ellos, que puede ser importante conocer:

  •  El conjunto de caracteres original, sobre el cual están basados todos los demás es el ASCII
  • El ASCII funciona perfectamente con el idioma inglés pero no sirve para los demás idiomas ya que no tiene vocales acentuadas ni vocales con diéresis ni eñes ni otros caracteres que se usan en otros idiomas
  • En un conjunto de caracteres se le asigna un número a cada carácter
  • En el ASCII esos números van desde el 0 hasta el 127. Dentro de esos 128 caracteres hay 32 que son invisibles y sirven para control (tecla ENTER, tecla TAB, tecla ESC, etc.)
  • Los números desde el 128 hasta el 255 están libres y pueden ser usados por otros conjuntos de caracteres
  • Un ejemplo son los llamados ISO8859 que están muy difundidos. Hay varias versiones, cada una de esas versiones usa los 128 caracteres sobrantes en su propia manera. Los caracteres desde el 128 hasta el 159 no están asignados y pueden ser usados para caracteres de control. Los caracteres adicionales que necesitan los distintos idiomas (español, portugués, francés, alemán, polaco, serbio, ruso, etc.) se codifican desde el 160 hasta el 255
  • El conjunto de caracteres ISO8859_1 tiene todos los caracteres de los idiomas europeos occidentales. Es el más ampliamente usado de los ISO8859 ya que permite escribir en: afrikaans, albanés, alemán, catalán, danés, escocés, español, finés, francés, holandés, inglés, islandés, italiano, noruego, portugués, rumano, suaheli, sueco, vasco
  • El conjunto de caracteres ISO8859_2 tiene todos los caracteres de los idiomas europeos centrales: checo, eslovaco, esloveno, polaco, etc.
  • Hay varios ISO8859 más, cada uno de ellos conteniendo los caracteres necesarios para escribir en distintos idiomas europeos
  • Los idiomas del este de Asia no pueden ser codificados con un solo byte ya que esos idiomas tienen muchos miles de caracteres, llamados ideogramas, y en un byte como máximo se pueden tener 256 caracteres. Por ese motivo se necesita de más de un byte para codificarlos
  • Esto implica que la cantidad de caracteres visibles es distinta a la cantidad de bytes necesarios para almacenarlos. En ASCII y en ISO8859 cada carácter ocupa exactamente un byte. En los idiomas de Asia oriental eso no es cierto, ya que cada carácter ocupa varios bytes.
  • Para unificar a todos los conjuntos de caracteres y evitar tantas incompatibilidades se inventó el UNICODE
  • Dentro de UNICODE hay tres posibilidades: UTF-8, UTF-16, UTF-32
  • Con UNICODE se pueden codificar hasta 1.114.112 caracteres distintos, pero la mayoría de ellos aún no están codificados
  • Como se pueden usar hasta 4 bytes por cada carácter lo más sencillo hubiera sido hacer eso, pero el espacio de almacenamiento sería muy grande, ya que para tener todos los caracteres usados por los lenguajes europeos con 2 bytes sería más que suficiente. Es por eso que se inventaron varias formas de codificación, las cuales empiezan con las siglas UTF. Las más usada es la UTF-8
  • Cuando se crea una Base de Datos se puede especificar cual conjunto de caracteres se usará por defecto en ella
  • Si todo el texto que será introducido en las columnas de tipo CHAR o VARCHAR estará escrito en alguno de los idiomas europeos occidentales (el español, entre ellos) usar ISO8859_1. Si existe la posibilidad de que estén escritos en otros idiomas europeos (checo, polaco, ruso, etc.) usar UTF-8.
  • Hasta la versión 2.5.3 el Firebird no dispone de la posibilidad de cambiar el conjunto de caracteres de una Base de Datos. Hay programas utilitarios como el IBEScript que sí tienen esa opción. Con Firebird 3.0 ya se podrá cambiar el conjunto de caracteres

Artículos relacionados:

Entendiendo a los conjuntos de caracteres

Funciones útiles con los conjuntos de caracteres

El índice del blog Firebird21

El foro del blog Firebird21

 

Entendiendo a los conjuntos de caracteres

3 comentarios

Los conjuntos de caracteres, también llamados juegos de caracteres en castellano, y en inglés CHARACTER SET son todos los caracteres que pueden ser guardados en una columna de tipo CHAR o VARCHAR. Dentro de un conjunto de caracteres a cada carácter se le asigna una posición que será siempre la misma en ese conjunto de caracteres. Por ejemplo, en el conjunto de caracteres ASCII la letra A mayúscula siempre se encuentra en la posición 65.

El conjunto de caracteres base es el llamado ASCII (American Standard Code for Information Interchange, código estándar norteamericano para el intercambio de la información), pronunciado áski, está compuesto por todas las letras mayúsculas, y minúsculas del alfabeto inglés, todos los dígitos, y algunos caracteres especiales. Usa los últimos 7 bits de un byte y por lo tanto tiene 128 caracteres (ya que 2 elevado a la 7ª potencia es 128).

CHARACTER_SET_01

Captura 1. Si haces clic en la imagen la verás más grande

Este conjunto de caracteres es muy bueno … si todo el texto estará escrito en inglés moderno. Pero si quieres escribir texto en español, en portugués, en francés, en chino, en vietnamita, etc., no te servirá porque te faltarán caracteres, en el caso de escribir texto en español encontrarás que te faltan las vocales acentuadas, las letras u con diéresis y las letras eñe.

El mismo problema tendrás si quieres escribir texto en portugués, en francés, en alemán, en ruso, en chino, etc., no tendrás todos los caracteres que necesitas.

Por ese motivo se inventaron otros conjuntos de caracteres, hay un montón de ellos, para contemplar todos los casos posibles. Por ejemplo tenemos al BIG_5 que tiene los caracteres chinos, japoneses y coreanos, el CYRL que tiene los caracteres cirílicos (usados en el idioma ruso), el DOS737 que tiene los caracteres griegos, el DOS862 que tiene los caracteres hebreos, el DOS864 que tiene los caracteres árabes, etc.

Como vimos anteriormente, el conjunto de caracteres ASCII usa solamente los últimos 7 bits de cada byte. Como sobra el bit más significativo entonces se pueden codificar 128 caracteres más. Hay por supuesto muchísimas formas de realizar esa codificación, la más usada es la ISO8859, que tiene varias variantes.

ISO8859_1 tiene todos los caracteres que se necesitan en alemán, danés, español, finés, francés, holandés, inglés, islandés, italiano, noruego, portugués, sueco. Por ese motivo normalmente se lo llama «europeo occidental» o también «Latin 1».

ISO8859_2 tiene todos los caracteres que se necesitan en checo, croata, eslovaco, esloveno, húngaro, polaco, rumano, serbio. Por ese motivo se lo llama «europeo central» o también «Latin 2».

Hay muchos ISO8859 más, que sirven para introducir texto en muchísimos idiomas, pero no en todos. Los idiomas coreano, chino, japonés, etc., no pueden ser usados con ISO8859, ya que esos idiomas tienen más de 128 caracteres distintos.

Pero tener tantos conjuntos de caracteres era muy problemático cuando se quería intercambiar información entre computadoras ¿por qué? porque con los primeros 128 caracteres no había problemas pero con los demás sí. Por ejemplo, con un conjunto de caracteres el carácter ubicado en la posición 163 era la ú (una letra u minúscula acentuada), y con otro conjunto de caracteres en la posición 163 estaba la letra griega mu. Misma posición, distinto símbolo. Muy complicado.

Por ese motivo se decidió inventar un conjunto de caracteres universal, que sirviera siempre y para todos los casos.

A ese estándar universal se le llamó UNICODE.

Mediante UNICODE se puede escribir texto en cualquier idioma conocido, tanto moderno como antiguo, pero además puedes utilizar símbolos especiales matemáticos, notas musicales, flechas, iconos, etc. Eso es posible porque con UNICODE pueden usarse hasta 4 bytes. Si se usaran todos los bits para representar caracteres entonces podríamos tener 2 elevado a la 32, o sea 4.294.967.296 caracteres distintos pero no es así, algunos caracteres son de control, por lo que en realidad solamente se pueden codificar hasta 1.114.112 caracteres distintos, de todas maneras más que suficientes para todas nuestras necesidades actuales y futuras.

Algo que debes recordar es que UNICODE no está terminado, en cada nueva versión se le agregan más símbolos. Pero no te preocupes, ya tiene todos los caracteres usados en todos los lenguajes conocidos, lo que se le va agregando son símbolos. Por ejemplo el símbolo del euro se le agregó en el año 1998, antes de eso no lo tenía porque no podían adivinar que existiría una moneda llamada euro ni cual sería su símbolo.

Cuando en UNICODE se codifican los bits para representar caracteres, hay 3 formas usuales de hacerlo, todas ellas empiezan con las letras UTF (Unicode Transformation Format), y son: UTF-8, UTF-16, UTF-32.

Los números indican cuantos bits se usan en cada grupo de caracteres, no cuantos bits se guardarán.

¿Y qué tiene que ver todo esto con Firebird?

Que en Firebird todo el texto que se introduce en una columna de tipo CHAR o VARCHAR debe pertenecer sí o sí a un conjunto de caracteres.

Cuando creas una Base de Datos debes especificar cual conjunto de caracteres se usará por defecto en ella.

Si no lo especificas entonces se usará NONE. Lo cual es bueno si todo el texto estará escrito en inglés, pero si no es así entonces tendrás problemas cuando quieras usar la función UPPER(), entre otras cosas.

Ejemplo:

Se creó una Base de Datos y se especificó como conjunto de caracteres a NONE. Luego se creó una tabla llamada TEST con una columna llamada NOMBRE de tipo VARCHAR(40), se le insertaron dos filas a esa tabla, y luego se consultó esa tabla:

INSERT INTO TEST (NOMBRE) VALUES('aeiou AEIOU');
INSERT INTO TEST (NOMBRE) VALUES('áéíóú üÜ ñÑ');

SELECT UPPER(NOMBRE) FROM TEST

El resultado obtenido fue:

CHARACTER_SET_02

Captura 2. Si haces clic en la imagen la verás más grande

y como puedes ver, las letras del alfabeto inglés sí fueron convertidas a mayúsculas, pero las demás letras no.

Por lo tanto, lo que debemos hacer al crear una Base de Datos es especificar un conjunto de caracteres que contemple todas las letras que se pueden usar en español y que también nos permita ordenar correctamente, y convertir a mayúsculas.

Los dos conjuntos de caracteres más utilizados para lograr ese objetivo son ISO8859_1 y UTF8.

¿Y cuál de ellos es preferible usar?

Es mejor usar ISO8859_1 porque cada carácter siempre ocupa exactamente 1 byte. En cambio si usamos UTF8 cada carácter que no sea ASCII ocupará 2 bytes y estaremos desperdiciando mucho espacio en el disco duro. La excepción a esta regla es si sabes que necesitarás intercambiar datos con bases de datos que usen conjuntos de caracteres que no sean europeos occidentales, por ejemplo con algún ucraniano o algún ruso. Pero para la gran generalidad de los casos, tu mejor opción es usar ISO8859_1.

¿Se puede cambiar el conjunto de caracteres de una Base de Datos?

Supongamos que al crear tu Base de Datos especificaste a UTF8 como su conjunto de caracteres y luego quieres cambiarlo a ISO8859_1 porque es más conveniente ya que se ahorra espacio, ¿puedes hacerlo?

No directamente con el Firebird, pero sí con algunos programas utilitarios como el IBEScript.

¿Y por qué no se puede con Firebird?

Podrías pensar que sería conveniente tener una alternativa como:

ALTER DATABASE ALTER DEFAULT CHARACTER SET ISO8859_1;

pero tal cosa no existe. ¿Por qué no? Porque en tu Base de Datos podrías tener millones de filas que tienen columnas de tipo CHAR o VARCHAR cuyo conjunto de caracteres debería ser cambiado. Y eso tomará un montón de tiempo. Podrías pensar: «bueno, que deje a las columnas como están y que use ISO8859_1 para el nuevo texto», pero eso provocaría inconsistencias. Por ejemplo, al crear la Base de Datos especificaste un conjunto de caracteres que te permite escribir en chino, luego cambiaste de idea y quieres escribir en español. ¿Y las columnas que ya tienen texto escrito en chino? No pueden ser borradas, ni traducidas por el Firebird ya que esa no es su tarea y no puede traducir de cada uno de los cientos de idiomas a cada uno de los otros cientos de idiomas.

Es por ese motivo que debes ser muy cuidadoso al elegir un conjunto de caracteres, ya que si eliges al equivocado luego será muy problemático cambiarlo. Hay programas utilitarios que te permiten realizar esa tarea pero en bases de datos muy grandes el tiempo que se demorarán se cuenta en muchas horas y quizás hasta en días. No es algo que les tomará un minuto o dos minutos terminar.

Sin embargo, en Firebird 3.0 si se tendrá la opción de cambiar el conjunto de caracteres por defecto. La sintaxis prevista es:

ALTER DATABASE
SET DEFAULT CHARACTER SET <nuevo_conjunto_de_caracteres>

Pero el autor de este blog aún no sabe en que condiciones se podrá realizar, ni cuanto tiempo se demorará la tarea de cambiar el conjunto de caracteres en bases de datos muy grandes.

Algo muy relacionado con el CHARACTER SET es lo que se llama COLLATE, que nos permite especificar como serán ordenados los caracteres. Para el lenguaje español es muy sencillo, siempre debemos elegir ES_ES.

Por lo tanto, al crear una Base de Datos que en sus columnas CHAR y VARCHAR podrá tener cualquiera de los caracteres del idioma español lo que debemos escribir es:

CREATE DATABASE 'MiBaseDatos.FDB'
DEFAULT CHARACTER SET ISO8859_1
COLLATION ES_ES;

Artículos relacionados:

Algo más sobre los conjuntos de caracteres

Funciones útiles con los conjuntos de caracteres

Entendiendo COLLATE

Consultando sin importar mayúsculas ni acentos

El índice del blog Firebird21

El foro del blog Firebird21

Validando un e-mail

Deja un comentario

A veces necesitamos verificar que el e-mail que el usuario introdujo sea un e-mail válido, es decir que cumpla con las reglas para ser usado como tal.

¿Cómo lo validamos?

Bien, hay varias formas de hacerlo pero probablemente la más inteligente sea usando expresiones regulares.  Mediante una expresión regular comparamos un string cualquiera con un patrón de caracteres. El resultado de esa comparación puede ser verdadero o falso, desde luego.

Entonces, para validar un e-mail usando expresiones regulares podríamos escribir algo como:

SELECT
   IIF('minombre@midominio.com' SIMILAR TO '[[:ALNUM:]-_.]*@[[:ALNUM:]-_.]*', 'válido', 'no válido')
FROM
   RDB$DATABASE

El e-mail que queremos validar es minombre@midominio.com y para ello en el SELECT usamos SIMILAR TO. Al usar SIMILAR TO le estamos diciendo al Firebird que usaremos una expresión regular.

¿Y qué significa todo lo que está a continuación de SIMILAR TO?

:ALNUM: es la abreviación de alfanumérico, es decir que incluye todos los caracteres desde la ‘a’ hasta la ‘z’, desde la ‘A’ hasta la ‘Z’ y desde el ‘0’ hasta el ‘9’.

* significa que el caracter precedente puede encontrarse 0 ó muchas veces

@ significa que sí o sí debe existir el carácter @ en esa posición

[] significa que es una clase, o sea cualquiera de los miembros de esa clase pueden existir

Entonces, en castellano lo que dice esa expresión regular es: «Cualquier carácter alfanumérico, el guión, el guión bajo y el punto, pueden repetirse entre cero y muchas veces. El símbolo de arroba debe existir, es obligatorio. Y luego cualquier carácter alfanumérico, el guión, el guión bajo y el punto, pueden repetirse entre cero y muchas veces.»

Entonces, ahora nos falta verificar que realmente con esa expresión regular podemos validar e-mails, así que probamos con varios de ellos, como:

‘minombre@midominio.com’

‘MiNombre@MiDominio.com’

‘MiNombre123@MiDominio.com’

‘Mi_Nombre_123@Mi_Dominio.com’

‘Mi_Nombre_123@Mi_Dominio.com.py’

Y vemos que con todos ellos funciona perfectamente. Así que ahora probamos con e-mails que sabemos inválidos, como los siguientes:

‘minombremidominio’

‘minombremidominio.com’

‘.com’

Y vemos que efectivamente son rechazados.

Bien, la validación no es perfecta ya que acepta los siguientes e-mails:

‘@com’

‘@.com’

Pero de todas maneras es de una gran ayuda y simple de escribir. Hay varias formas de validar que no empiece con @, una de ellas es la siguiente:

SELECT
   IIF('@com' SIMILAR TO '[[:ALNUM:]-_.]*@[[:ALNUM:]-_.]*' and
       SUBSTRING('@com' FROM 1 FOR 1) <> '@', 'válida', 'no válida')
FROM
   RDB$DATABASE

Donde lo que hacemos es verificar que el primer carácter no sea una @. Desde luego que en general no estarás validando contra una constante de tipo string sino contra una columna. Por ejemplo para usarlo en un trigger podrías escribir algo como:

CREATE EXCEPTION E_EMAIL_NO_VALIDO 'El e-mail no es válido, verifícalo.';
CREATE TRIGGER BIU_CLIENTES FOR CLIENTES
   ACTIVE BEFORE INSERT OR UPDATE
   POSITION 1
AS
   DECLARE VARIABLE lcEmailOK CHAR(1);
BEGIN

   lcEmailOK = (SELECT
                   IIF(NEW.CLI_EMAILX
                   SIMILAR TO '[[:ALNUM:]-_.]*@[[:ALNUM:]-_.]*' AND
                   SUBSTRING(NEW.CLI_EMAILX FROM 1 FOR 1) <> '@', 'T', 'F')
                FROM
                   RDB$DATABASE);

   IF (lcEmailOK = 'F') THEN
      EXCEPTION E_EMAIL_NO_VALIDO;

END;

La gran mayoría de los usuarios si escriben mal un e-mail es porque se equivocaron al hacerlo, no por maldad sino por una equivocación humana. Para detectar algunas de esas equivocaciones podríamos mejorar un poco el trigger anterior, que ahora quedaría así:

CREATE TRIGGER BIU_CLIENTES FOR CLIENTES
   ACTIVE BEFORE INSERT OR UPDATE
   POSITION 0
AS
   DECLARE VARIABLE lcEmailOK CHAR(1);
BEGIN

   lcEmailOK = (SELECT
                   IIF(NEW.CLI_EMAILX
                   SIMILAR TO '[[:ALNUM:]-_.]*@[[:ALNUM:]-_.]*' AND
                   SUBSTRING(NEW.CLI_EMAILX FROM 1 FOR 1) <> '@', 'T', 'F')
                FROM
                   RDB$DATABASE);
   
   IF (lcEmailOK = 'T') THEN
      lcEmailOK = IIF(NEW.CLI_EMAILX CONTAINING '--', 'F', lcEmailOK);
   
   IF (lcEmailOK = 'T') THEN
      lcEmailOK = IIF(NEW.CLI_EMAILX CONTAINING '__', 'F', lcEmailOK);
   
   IF (lcEmailOK = 'T') THEN
      lcEmailOK = IIF(NEW.CLI_EMAILX CONTAINING '..', 'F', lcEmailOK);
   
   IF (lcEmailOK = 'F') THEN
      EXCEPTION E_EMAIL_NO_VALIDO;

END;

Donde lo que hacemos es verificar que no haya escrito dos guiones seguidos, dos guiones bajos seguidos, o dos puntos seguidos. Ninguna de esas posibilidades es normalmente usada en un e-mail, así que las rechazamos. Desde luego que podrías agregar otras comparaciones si te parecen necesarias.

Y de esta manera siempre que el usuario esté intentando insertar o actualizar los datos de un cliente se verificará que el e-mail de ese cliente sea un e-mail que cumple con las reglas mínimas para ser admitido como tal. Si no las cumple entonces se lanzará una excepción informándole del problema.

Artículos relacionados:

Los predicados de comparación

Usando SIMILAR TO

El índice del blog Firebird21

El foro del blog Firebird21

 

Mostrando los resultados ordenados por cualquier criterio

8 comentarios

Cuando en un SELECT usamos la cláusula ORDER BY le estamos indicando al Firebird en cual orden queremos que las filas sean mostradas. En general ese orden es fijo y ya lo conocemos antes de escribir el SELECT. Sin embargo, en ocasiones no ocurre así sino que el orden de las filas depende de alguna condición.

Ejemplo:

Tenemos una tabla llamada PRODUCTOS la cual tiene las siguientes filas:

ORDEN1

Captura 1. Si haces clic en la imagen la verás más grande

Y queremos mostrar a esas filas ordenadas según un criterio muy particular, y no tenemos un índice creado que podamos usar. En este caso, lo que queremos es mostrar primero a todas las filas en cuyo nombre esté «350», luego las filas en cuyo nombre está la palabra «LITRO» y luego las filas en cuyo nombre está la palabra «LITROS».

Resumiendo:

  • Primero las filas que tienen «350»
  • Después las filas que tienen «LITRO»
  • Después las filas que tienen «LITROS»

Con el siguiente SELECT … ORDER BY obtendemos lo que buscamos:

SELECT
   PRD_IDENTI,
   PRD_NOMBRE,
   CASE
      WHEN PRD_NOMBRE CONTAINING '350'    THEN 1
      WHEN PRD_NOMBRE CONTAINING 'LITROS' THEN 3
      WHEN PRD_NOMBRE CONTAINING 'LITRO'  THEN 2
   END
FROM
   PRODUCTOS
ORDER BY
   CASE
      WHEN PRD_NOMBRE CONTAINING '350'    THEN 1
      WHEN PRD_NOMBRE CONTAINING 'LITROS' THEN 3
      WHEN PRD_NOMBRE CONTAINING 'LITRO'  THEN 2
   END

El primer CASE … END es opcional, no necesitamos escribirlo pero si lo escribimos nos ayuda a entender lo que sucede. El resultado será el siguiente:

ORDEN2

 Captura 2. Si haces clic en la imagen la verás más grande

Entonces ¿por qué funciona lo que escribimos en la cláusula ORDER BY? porque hemos creado una columna virtual, y las filas se muestran ordenadas según esa columna virtual. O sea, primero todas las que tiene el valor 1, luego las que tienen el valor 2 y finalmente las que tienen el valor 3.

Desde luego que podríamos tener más valores si los necesitamos: 4, 5, 6, 7, …., etc.

¿Y por qué los WHEN que escribimos no están ordenados de menor a mayor?

Porque los caracteres «LITRO» está incluidos dentro de los caracteres «LITROS». Si hubiéramos escrito primero el WHEN que tiene «LITRO» y luego el WHEN que tiene «LITROS» entonces no habríamos obtenido el resultado deseado. ¿Por qué? porque en ese caso «LITROS» habría tenido el valor 2 y no el valor 3, que es el que necesitamos.

Conclusión:

Es importante recordar que podemos mostrar a las filas por cualquier orden que se nos ocurra, y que no es necesario tener un índice para ello, y que la condición puede ser cualquiera. La técnica es crear una columna virtual (la cual por supuesto no es necesario mostrársela a los usuarios) y así las filas serán mostradas según el orden en que las hayamos colocado en esa columna virtual.

En este ejemplo se mostró la columna virtual, pero eso es para que se entienda la técnica, a los usuarios no necesitamos mostrársela.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Usando una subconsulta en un JOIN

7 comentarios

Cuando escribimos un SELECT a veces necesitamos usar un JOIN para relacionar a un conjunto de resultados con otro conjunto de resultados. En general tiene esta forma:

SELECT
   MiColumna1,
   MiColumna2,
   MiColumna3
FROM
   MiTabla1
JOIN
   MiTabla2
      ON MiCondición

Lo que mucha gente no sabe es que en el JOIN no es imprescindible que especifiquemos una tabla, también podemos especificar un SELECT si lo necesitamos. Y nos quedaría de esta forma:

SELECT
   MiColumna1,
   MiColumna2,
   MiColumna3
FROM
   MiTabla1
JOIN
   (SELECT
       MiColumna4,
       MiColumna5,
       MiColumna6
    FROM
       MiTabla2
    WHERE
       MiCondición1) AS MiAlias
   ON MiCondición2

¿Qué podemos notar acá?

  1. Que la subconsulta (o sea, el segundo SELECT ) se encuentra rodeada por paréntesis
  2. Que la subconsulta tiene un alias (que se encuentra después del AS y puede ser cualquiera, «MiAlias» es sólo un ejemplo)
  3. Que en «MiCondición2» debemos usar ese alias

Ejemplo 1:

SELECT
   M.MVC_FECHAX,
   M.MVC_TIPDOC,
   M.MVC_NRODOC,
   M.MVC_IDECLI,
   MJ.CLI_NOMBRE
FROM
   MOVIMCAB M
JOIN
   (SELECT
       CLI_IDENTI,
       CLI_NOMBRE
    FROM
       CLIENTES) AS MJ
   ON M.MVC_IDECLI = MJ.CLI_IDENTI

Este ejemplo es muy sencillo, y solamente sirve para ilustrar el concepto. No es necesario usar una subconsulta para algo tan simple pero está ahí para que se entienda como funciona.

Como puedes ver, la subconsulta tiene una alias (en este caso ese alias se llama MJ) y es ese alias el que usamos en la condición que hace la relación (o sea, lo que escribimos después del ON).

Ejemplo 2:

Ahora queremos saber los siguientes datos para cada venta realizada:

  1. La fecha de la venta
  2. El número de la Factura de venta
  3. El nombre del cliente
  4. La cantidad de productos distintos que le vendimos
  5. El total de la Factura
SELECT
   C.MVC_FECHAX,
   C.MVC_NRODOC,
   L.CLI_NOMBRE,
   D.CANTIDAD,
   D.TOTALVENTA
FROM
   MOVIMCAB C
JOIN
   (SELECT
       MOV_IDECAB,
       COUNT(*) AS CANTIDAD,
       SUM(MOV_CANTID * MOV_PRECIO) AS TOTALVENTA
    FROM
       MOVIMDET
    GROUP BY
       MOV_IDECAB) AS D
   ON C.MVC_IDENTI = D.MOV_IDECAB
JOIN
   CLIENTES L
      ON C.MVC_IDECLI = L.CLI_IDENTI

Como puedes ver, ahora la subconsulta es más compleja pero también mucho más útil: ya nos da la información que estábamos necesitando.

Nuestra tabla MOVIMCAB tiene estas filas:

JOIN1

Captura 1. Si haces clic en la imagen la verás más grande

Nuestra tabla MOVIMDET tiene estas filas:

JOIN2

 

Captura 2. Si haces clic en la imagen la verás más grande

Nuestra tabla de CLIENTES tiene estas filas:

JOIN3

Captura 3. Si haces clic en la imagen la verás más grande

Y el resultado que obtenemos es el siguiente:

JOIN4Captura 4. Si haces clic en la imagen la verás más grande

Entonces aquí tenemos lo que estábamos buscando.

Desde luego que no es la única forma de resolver este problema pero este ejemplo sirve para ilustrar el concepto de que podemos tener subconsultas en un JOIN y que eso puede sernos muy útil en algunas ocasiones. En otras palabras, tenemos una técnica más para utilizar con los SELECTs.

Conclusión:

Podemos tener subconsultas en los JOINs y eso es algo muy bueno porque nos abre un buen abanico de posibilidades. Lo que debemos recordar es que la subconsulta debe estar rodeada por paréntesis y que debemos asignarle un alias. Solamente eso, el resto es igual a los demás JOINs que ya conocemos.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21

Cantidad de conexiones concurrentes

5 comentarios

Cuando usamos Firebird lo normal es que varios usuarios estén conectados a la misma Base de Datos y al mismo tiempo. Hay excepciones, por supuesto, que pueden ser por diseño: estamos usando la versión embedded, o porque casi todos se fueron a su casa y uno solo se quedó trabajando.

Entonces la pregunta es: ¿cuántos usuarios pueden estar conectados concurrentemente a una Base de Datos?

Concurrentemente significa «al mismo tiempo».

Pues bien, eso depende de la versión del Firebird y de la arquitectura que estemos usando.

SuperServer, hasta la versión 2.5.2, 1024 usuarios concurrentes. Desde la versión 2.5.3, 2048 usuarios concurrentes.

SuperClassic, hasta la versión 2.5.2, 1024 usuarios concurrentes. Desde la versión 2.5.3, 2048 usuarios concurrentes.

Classic, no tiene límites. Depende solamente de la memoria RAM disponible.

Artículos relacionados:

El índice del blog Firebird21

El foro del blog Firebird21