Esta página fue traducida automáticamente. Lee el original en inglés. English

Biblioteca de IBSurgeon

Tipos de datos

NOTICE: Este documento es el capítulo del libro “The InterBase World” que fue escrito por Alexey Kovyazin y Serg Vostrikov.

A pesar de que los tipos de datos están descritos en detalle en la documentación (ver [1, capítulo 4.), es necesario considerar una serie de nociones que se utilizarán con frecuencia en los siguientes capítulos de este libro. Además de la información general, también se revisarán varios ejemplos de uso de tipos de datos en bases de datos InterBase y recomendaciones sobre su uso y conversión. Consideraremos en detalle las diferencias de tipos de datos que existen en el 1er y 3er dialecto de base de datos InterBase.

Acerca de los datos

Los tipos de datos son elementos básicos de cualquier lenguaje de programación o de cualquier servidor DBMS. InterBase no es la excepción. Cuando decimos que una base de datos almacena cierta información, debemos darnos cuenta de que esta información no puede almacenarse en un solo lugar. Es al contrario; los datos deben clasificarse y colocarse en su “estante”. Los tipos de datos definen qué se puede poner en un cierto “estante” y qué no. Cuando hablamos del “estante”, en primer lugar nos referimos a los campos de las tablas de la base de datos (ver capítulo “Tablas. Claves primarias y generadores” (parte 1)), así como a las variables dentro de los disparadores y procedimientos almacenados, etc. Cada tipo de datos tiene un conjunto de operaciones que se pueden ejecutar sobre los valores de este tipo. Por lo tanto, es importante elegir el tipo de datos correcto al diseñar una base de datos. Esto ayudará a evitar muchos problemas al desarrollar programas de clientes. En InterBase hay 12 tipos de datos que pueden satisfacer los requisitos del desarrollador para almacenar datos. Estos tipos se subdividen condicionalmente en los siguientes 6 grupos:

  • para almacenar enteros - INTEGER y SMALLINT;
  • para almacenar números reales - FLOAT y DOUBLE PRECISION;
  • para almacenar números con precisión fija - NUMERIC y DECIMAL;
  • para almacenar fecha, hora y marca de tiempo - DATE, TIME y TIMESTAMP;
  • para almacenar símbolos - CHARACTER (en forma abreviada - CHAR) y VARYING CHARACTER (VARCHAR);
  • para almacenar datos dinámicamente extensibles - BLOB

Además, es posible definir matrices de valores de tipos primitivos, es decir, todos los tipos enumerados excepto BLOB.

La mayoría de los tipos de datos de InterBase corresponden a los tipos definidos en el estándar SQL92, sin embargo, aparte de esto, tienen sus propias peculiaridades: matrices de tipos de datos primitivos y BLOB. Las matrices en InterBase pueden contener un conjunto de datos del mismo tipo en un solo campo. Por ejemplo, podemos definir una matriz de valores de tipo INTEGER. Las matrices pueden tener varias dimensiones. El tipo de datos BLOB es un tipo de datos dinámicamente extensible, cuyo nombre a menudo se descifra como Binary Large OBject. Cabe decir que BLOB es una invención de los desarrolladores de InterBase que luego se extendió y se estableció en todos los servidores SQL contemporáneos.

Sintaxis de definición de tipos de datos

Los tipos de datos se utilizan para describir campos en tablas, variables en disparadores y procedimientos almacenados. La sintaxis común para definir todos los tipos de datos posibles en InterBase se proporciona a continuación.

< datatype> =

{SMALLINT | INTEGER | FLOAT | DOUBLE PRECISION}[ ]

| {DATE | TIME | TIMESTAMP} [ ]

| {DECIMAL | NUMERIC} [( precision [, scale])] [ ]

| {CHAR | CHARACTER | CHARACTER VARYING | VARCHAR} [( int)

[ ] [CHARACTER SET charname]

| {NCHAR | NATIONAL CHARACTER | NATIONAL CHAR}

[VARYING] [( int)] [ ]

| BLOB [SUB_TYPE { int | subtype_name}] [SEGMENT SIZE int]

[CHARACTER SET charname]

| BLOB [(seglen [, subtype])]

Las características de los tipos de datos, como tamaño, precisión y rango de valores posibles, se describen en detalle en la tabla 4.1 en [1., por lo tanto, no nos repetiremos aquí. Ahora revisemos brevemente las principales peculiaridades de los tipos de datos y centrémonos en su posible aplicación.

Tipos enteros

SMALLINT y INTEGER se refieren a tipos enteros. Debo decir que SMALLINT representa una versión limitada de INTEGER. Su longitud es de 2 bytes, a diferencia de los 4 destinados para almacenar INTEGER. Por lo general, no debería ahorrar en espacio en disco. Por esta razón, es mejor usar el tipo INTEGER para almacenar valores enteros.

El área de aplicación de los tipos enteros es obvia: son necesarios para campos que contienen solo enteros - para almacenar contadores, números, etc. Por lo general, el tipo INTEGER también tiene los campos que contienen claves primarias.

Tipos de datos reales

Los tipos FLOAT y DOUBLE PRECISION se relacionan con los reales (también se les llama tipos de números con punto flotante). En primer lugar, quiero advertir al lector contra el uso del tipo FLOAT - su precisión no es suficiente para almacenar la mayoría de los valores fraccionarios. Especialmente no se recomienda almacenar valores monetarios en él - en variables de tipo FLOAT los errores de redondeo aparecen muy rápidamente y puede sorprender a un contador al hacer cálculos. La mejor manera de almacenar números con punto flotante (por ejemplo, en sistemas contables y sistemas para cálculos científicos) en una base de datos es almacenarlos en tipo DOUBLE PRECISION.

Debe tener en cuenta que en el 3er dialecto de InterBase existe un mecanismo para almacenar tipos con punto fijo de 64 bytes. Este mecanismo se utiliza para almacenar valores monetarios. El uso de estos tipos proporciona la mejor precisión.

Tipos de datos con punto fijo

NUMERIC y DECIMAL se refieren a estos tipos de datos. La pregunta sobre la diferencia entre NUMERIC y DECIMAL suena muy a menudo. Ambos tipos tienen una capacidad de dígitos idéntica: de 1 hasta 18 signos, precisión idéntica: de cero hasta una capacidad de dígitos.

Recordemos que: la capacidad de dígitos es el número total de dígitos entre, y la precisión: un número de signos después de la coma.

Lo más divertido es que estos tipos difieren en la capacidad de dígitos máxima según la documentación, pero en realidad, se realizan prácticamente igual y no hay diferencia entre ellos.

Puede verificarlo fácilmente, iniciando la utilidad isql y realizando la secuencia de acciones mencionada a continuación. Creamos la tabla de la siguiente vista:

SQL> CREATE TABLE test (

CON> Num_field NUMERIC(15,2),

CON> Dec_field DECIMAL(15,2));

Luego damos un comando para mostrar la estructura de la tabla:

SQL> show tables test;

Y vemos lo siguiente

NUM_FIELD NUMERIC(15, 2) Nullable

DEC_FIELD NUMERIC(15, 2) Nullable

Como puede ver, InterBase informa que ambas columnas dadas tienen tipo NUMERIC. Las razones de tal comportamiento residen en la realización de tipos de datos con punto fijo. El asunto es que InterBase tiene solo tres mecanismos para almacenar cualquier expresión entera, y todos los tipos, como quiera que se llamen, se realizan según estas variantes.

Aquí está la tabla de [1., que ilustra cómo se almacenan varios tipos enteros (tabla 1.1). Como puede ver, el almacenamiento de datos en el 3er dialecto es diferente para números con gran capacidad de dígitos:

Tabla 1.1. Almacenamiento de números con punto fijo

Capacidad de dígitos Dialecto 1 Dialecto 3
de 1 a 4 SMALLINT para NUMERIC
INTEGER para DECIMAL
SMALLINT
de 5 a 9 INTEGER INTEGER
de 10 a 18 DOUBLE PRECISION INT64

Ahora podemos decir con certeza cuáles son las principales diferencias entre los tipos NUMERIC y DECIMAL: en caso de definir un campo (o variable) con una pequeña capacidad de dígitos (hasta cuatro), el primero se almacena como entero de 2 bytes SMALLINT, y el segundo - como INTEGER de 4 bytes. Por lo tanto, si una capacidad de dígitos es más de cuatro, los tipos DECIMAL y NUMERIC serán equivalentes.

Preste atención a la diferencia de realización de tipos con gran capacidad de dígitos en el primer y tercer dialecto. En el primer dialecto, el número con punto fijo se convertía de entero a real, donde se aplicaban los mecanismos de redondeo. En el tercer dialecto esta peculiaridad ha sido eliminada: los grandes enteros se almacenan realmente como enteros - usando el mecanismo INT64 que puede almacenar números de 64 bits en un rango +/-2^32. Por lo tanto, sería mejor almacenar los datos sobre fondos monetarios en las bases de datos creadas con el uso del 3er dialecto. Solo usando el mecanismo INT64 se garantizará la seguridad de los pequeños restos monetarios.

Tipos para almacenar fecha y hora

Los tipos para almacenar fecha y hora han cambiado en la versión InterBase 6.x y sus clones en comparación con 4.x y 5.x. Para no confundirse en las telarañas históricas con estos tipos, consideraremos una situación en la versión InterBase 6. Luego, basándonos en ella, mencionaremos brevemente qué era antes. Esto se hace para aquellos usuarios que aún trabajan con versiones tempranas de InterBase. Entonces, hay 3 tipos en InterBase 6.x para almacenar fecha y hora: DATE, TIME y TIMESTAMP.

  • El tipo DATE almacena fechas con precisión de un día. Un rango de valores posibles: desde el 1 de enero de 100 d.C. hasta el 29 de febrero de 32768.
  • El tipo TIME almacena datos sobre la hora con precisión de una diezmilésima de segundo. Un rango de valores posibles: desde 00:00 AM hasta 23:59.9999 PM.
  • El tipo TIMESTAMP representa una combinación de los tipos DATE y TIME.

¿Cómo trabajar con fechas? Si la pregunta se trata del trabajo a nivel de servidor en procedimientos almacenados o disparadores, todo es bastante simple: siempre podemos declarar una variable del tipo requerido y establecerla desde las tablas y viceversa. Sin embargo, es necesario transferir los datos de una base de datos a la aplicación y viceversa. En este caso hay dos enfoques: usar bibliotecas que aplican un formato original de fechas de InterBase para el acceso a objetos de estos tipos y convertir este formato a tipos ordinarios de fecha/hora intralenguaje (FIBPlus es el ejemplo de tal biblioteca), o usar el mecanismo de transformar fechas a líneas, integrado en InterBase.

¿Qué hará si necesita extraer solo el año o el mes de la fecha completa? Tendrá que usar un grupo de funciones EXTRACT para este propósito (disponibles en todos los clones de InterBase 6.x) que le permiten extraer solo la parte requerida de la fecha. Estas funciones se usan de la siguiente manera:

EXTRACT (MONTH FROM DATE_FIELD)

EXTRACT (YEAR FROM DATE_FIELD)

La lista completa de parámetros en la función EXTRACT es la siguiente: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, WEEKDAY, YEARDAY. Su función se deduce de su nombre, por lo tanto, no los interpretaremos aquí.

Tipos de datos para almacenar texto

Hay dos tipos en InterBase destinados a almacenar información de texto - CHAR y VARCHAR. Sus nombres completos - CHARACTER y CHARACTER VARYING, sin embargo, no hay razón para usar nombres largos - incluso el comando Show tables en la utilidad isql da nombres breves de tipos.

Para definir un campo o una variable de tipo simbólico, es necesario especificar entre paréntesis después de un nombre de tipo un número de símbolos que se utilizarán en un objeto definido, u omitir un número de símbolos - así se creará el campo con una longitud de 1 símbolo.

CREATE TABLE testCHARLen(

Field1 CHAR(255),

Field2 CHAR);

Cuando se crea esta tabla, Field1 tendrá una longitud de 255 símbolos, y Field2 - 1 símbolo.

Los tipos CHAR y VARCHAR en muchos aspectos son similares: ambos pueden contener hasta 32768 símbolos, sin embargo, hay algunas diferencias. Aunque ambos tipos se almacenan en una base de datos de la misma manera, InterBase trabaja con ellos de diferentes formas. El siguiente ejemplo demuestra esto:

SQL> create table testCHAR ( c1 char(10), c2 varchar(10));

SQL> insert into testCHAR(c1,c2) values(‘Test’,‘Test’);

SQL> SELECT ‘(’||c1.|’)’, ‘(’||c2.|’)’ from testCHAR;

En el resultado, obtendremos lo siguiente:

(Test ) (Test)

Como puede ver, después del valor ‘Test’, elegido de un campo c1, había espacios en blanco. Esto significa que al seleccionar los datos de un campo de tipo CHAR, el valor devuelto se complementa con espacios en blanco hasta la longitud completa del campo. Es difícil suponer por qué tal comportamiento que lleva a un crecimiento sustancial del tráfico de red (carga de una red) es necesario. En cualquier caso, VARCHAR es un tipo simbólico recomendado para usar.

Una de las características principales del tipo simbólico es su conjunto de caracteres - CHARACTER SET. El conjunto de caracteres se define para toda la base de datos y se usa por defecto para todos los campos simbólicos si no se redefine explícitamente al crear un campo. Para crear un campo simbólico con la indicación explícita de un conjunto de caracteres, es necesario agregar la descripción de un conjunto de caracteres en la descripción de una columna (en las sentencias CREATE TABLE o ALTER TABLE). El conjunto de caracteres WIN1251 se usa generalmente para el soporte del ruso (si desea saber en detalle sobre el uso del ruso en InterBase, vea el capítulo “InterBase Russification” (parte 1)). Aquí hay un ejemplo de la tabla que contiene un campo simbólico con el conjunto de caracteres WIN1251 descrito explícitamente:

CREATE TABLE TestCHARSET(

Field1 VARCHAR(255),

Field2 VARCHAR(255) CHARACTER SET win1251);

Здесь Field1 - это поле без явного указания набора символов, поэтому для него будет использоваться набор символов, указанный при создании базы данных. Для поля Field2 очевидно определено, что оно будет хранить символы в кодировке WIN1251.

Помимо указания набора символов для символьных полей, можно также задать порядок сортировки (collation), который определяет, как будут сортироваться символы этого набора данных. Для русского языка существуют два варианта сортировки - WIN1251 и PXW_CYRL. Более подробно об использовании COLLATION ORDER см. в главе «Русификация InterBase».

Полный список наборов символов и применяемых для них COLLATION ORDER можно найти в документации [1, глава 13..

Внимание! Согласно документации по InterBase 6 существует 4 символьных типа: помимо вышеупомянутых типов данных существуют еще 2 - NCHAR и NCHAR VARYING, однако в той же документации ниже объясняется, что последние два типа - это те же типы, что и CHAR и VARCHAR, только с набором символов ISO8859.1 по умолчанию. Это означает, что фактически использование псевдотипа NCHAR эквивалентно применению CHAR DEFAULT CHARACTER SET ISO8859.1. Аналогично для NCHAR VARYING, только вместо CHAR используется VARCHAR. Очевидно, что применение этих псевдотипов предназначено для пользователей в Западной Европе и США, где набор символов ISO8859.1 создан для поддержки языков.

Тип данных BLOB

Тип данных BLOB предназначен для хранения большого количества данных переменного размера. Тип BLOB позволяет хранить данные, которые нельзя разместить в полях других типов, - например, изображения, музыкальные файлы, видеофрагменты и т. д. Требования к определению простейшего поля типа BLOB в таблице такие же, как и к определению поля любого элементарного типа:

CREATE TABLE testBLOB(

myBlobField BLOB);

В результате будет создано поле myBlobField, в котором можно хранить данные значительного размера. Несмотря на то, что поля BLOB не отличаются от других по способу определения, их реализация внутри базы данных сильно отличается. Не-BLOB-поля располагаются на странице данных (см. главу «Структура базы данных InterBase» (часть 4)) близко друг к другу, а на странице данных хранится только идентификатор BLOB, сам же BLOB размещается на специальной странице. Такая структура данных позволяет хранить данные нефиксированного размера.

Тип BLOB имеет возможность определения набора нескольких подтипов и специальных процедур, называемых фильтрами (BLOB filters), для работы с этими подтипами. В InterBase встроено несколько предопределенных подтипов BLOB. Все эти подтипы имеют неотрицательные номера, например подтип 0 - данные неопределенного типа, подтип 1 - текст, подтип 2 - BLR (Binary Language Representation, см. глоссарий и главу «Структура базы данных InterBase») и т. д. Пользователь также может определять подтипы BLOB, которые могут иметь отрицательные значения. Фильтр может применяться к каждому типу. Он преобразует поле одного подтипа в другой.

Следует отметить, что использование BLOB-полей обычно является альтернативой хранению внешних по отношению к базе данных файлов. Что касается BLOB-фильтров, они используются довольно редко из-за ориентации на узкую категорию задач.

Массивы

СУБД InterBase была одной из первых, в которых появились массивы. Поддержка массивов в базе данных является расширением традиционной реляционной модели. Наличие массивов позволяет упростить работу с наборами данных одного типа.

Массив - это коллекция значений одного типа, имеющая общее имя и позволяющая обращаться к любому элементу массива по его номеру. Массивы в InterBase могут быть одномерными и многомерными.

Чтобы создать в таблице поле массива чисел INTEGER, следует написать примерно следующее:

CREATE TABLE test(

myOneDimArray INTEGER[12.,

myTwoDimArray INTEGER[5,4.,

myThreeDimArray INTEGER[2,10,8.);

Таким образом, будут созданы три поля типа массив: myOneDimArray - поле, содержащее одномерный массив из 12 чисел, myTwoDimArray - содержащее двумерный массив (матрицу) - 5х4 целых чисел, и myThreeDimArray - поле, содержащее трехмерный массив 2х10х8. Следует отметить, что при таком определении элементы массива нумеруются начиная с «единицы», т. е. первый элемент имеет номер 1, второй - номер 2 и т. д. Если кто-то хочет задать границы массива самостоятельно, например от 0 до 5, следует указать определение поля следующим образом:

myArray INTEGER[0:5.

Массивы реализованы на основе полей типа BLOB, поэтому не стоит опасаться, что многомерный массив «засорит» вашу таблицу большим объемом данных: InterBase аккуратно разместит данные массива на отдельных страницах для оптимизации операций ввода-вывода в этих полях. Как использовать массивы? Они предоставляют удобный механизм для хранения объектов одного типа. Однако в 80 % случаев вместо массивов разработчики предпочитают хранить множественные данные в подчиненных (детальных) таблицах, поэтому массивы не так часто используются в клиентских приложениях СУБД InterBase. Это происходит потому, что библиотеки доступа, поставляемые с Delphi и C ++ Builder, такие как BDE и IBX, не умеют работать с массивами. Согласно документации по InterBase, с массивами можно работать с помощью препроцессора gpre, однако это не самый удобный способ для разработчика на Delphi/C ++ Builder. К счастью, в библиотеке FIBPlus есть поддержка полей-массивов в InterBase. Подробно об этом можно прочитать в главе «Особые возможности FIBPlus». Клиентская библиотека IBProvider, позволяющая создавать клиентские приложения для InterBase с использованием средств разработки компании Microsoft, также поддерживает работу с массивами (см. главу «Разработка клиентских приложений СУБД InterBase с использованием технологии Microsoft OLE DB» (часть 3)).

Заключение

Следует отметить, что невозможно рассказать о типах данных, не забегая вперед, поскольку они проникают во все ключевые области, связанные с разработкой приложений баз данных. Поэтому при чтении этой книги лучше использовать данную главу как краткий справочник, к которому можно обращаться всякий раз, когда нужно освежить основы InterBase.