Cette page a été traduite automatiquement. Lisez l'original en anglais. English

Bibliothèque IBSurgeon

Types de données

NOTICE: Ce document est un chapitre du livre « The InterBase World » écrit par Alexey Kovyazin et Serg Vostrikov.

Malgré le fait que les types de données soient décrits en détail dans la documentation (voir [1, chapitre 4.), il est nécessaire d’examiner une série de notions qui seront fréquemment utilisées dans les chapitres suivants de ce livre. Outre les informations générales, plusieurs exemples d’utilisation des types de données dans les bases de données InterBase et des recommandations sur leur utilisation et leur conversion seront également examinés. Nous étudierons en détail les distinctions entre les types de données existant dans les 1er et 3e dialectes de base de données InterBase.

À propos des données

Les types de données sont des éléments de base de tout langage de programmation ou de tout serveur SGBD. InterBase ne fait pas exception. Lorsque nous disons qu’une base de données stocke certaines informations, nous devons réaliser que ces informations ne peuvent pas être stockées en un seul endroit. C’est l’inverse ; les données doivent être triées et placées sur leur « étagère ». Les types de données définissent ce qui peut être placé sur une certaine « étagère » et ce qui ne le peut pas. Lorsque nous parlons de « l’étagère », nous entendons avant tout les champs des tables de la base de données (voir le chapitre « Tables. Clés primaires et générateurs » (partie 1)), ainsi que les variables dans les déclencheurs et les procédures stockées, etc. Chaque type de données possède un ensemble d’opérations qui peuvent être exécutées sur les valeurs de ce type. Il est donc important de choisir le bon type de données lors de la conception d’une base de données. Cela aidera à éviter de nombreux problèmes lors du développement de programmes clients. Dans InterBase, il existe 12 types de données qui peuvent satisfaire les exigences du développeur en matière de stockage des données. Ces types sont conditionnellement subdivisés en 6 groupes suivants :

  • pour stocker des entiers - INTEGER et SMALLINT ;
  • pour stocker des nombres réels - FLOAT et DOUBLE PRECISION ;
  • pour stocker des nombres à précision fixe - NUMERIC et DECIMAL ;
  • pour stocker la date, l’heure et l’horodatage - DATE, TIME et TIMESTAMP ;
  • pour stocker des symboles - CHARACTER (sous forme abrégée - CHAR) et VARYING CHARACTER (VARCHAR) ;
  • pour stocker des données à extension dynamique - BLOB

En outre, il est possible de définir des tableaux de valeurs de types primitifs, c’est-à-dire tous les types énumérés sauf BLOB.

La plupart des types de données InterBase correspondent aux types définis dans la norme SQL92, cependant, en plus de cela, il existe leurs propres particularités - les tableaux de types de données primitifs et BLOB. Les tableaux dans InterBase peuvent contenir un ensemble de données du même type dans un seul champ. Par exemple, nous pouvons définir un tableau de valeurs de type INTEGER. Les tableaux peuvent avoir plusieurs dimensions. Le type de données BLOB est un type de données à extension dynamique, dont le nom est souvent déchiffré comme Binary Large OBject. Il faut dire que BLOB est l’invention des développeurs d’InterBase qui s’est ensuite répandue et installée dans tous les serveurs SQL contemporains.

Syntaxe de définition des types de données

Les types de données sont utilisés pour décrire les champs dans les tables, les variables dans les déclencheurs et les procédures stockées. La syntaxe courante de définition de tous les types de données possibles dans InterBase est donnée ci-dessous.

< 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])]

Les caractéristiques des types de données telles que la taille, la précision et la plage de valeurs possibles sont décrites en détail dans le tableau 4.1 de [1., nous ne nous répéterons donc pas ici. Examinons maintenant brièvement les principales particularités des types de données et concentrons-nous sur leur application possible.

Types entiers

SMALLINT et INTEGER se réfèrent aux types entiers. Je dois dire que SMALLINT représente une version réduite d’INTEGER. Sa longueur est de 2 octets contrairement aux 4 prévus pour stocker INTEGER. En général, vous ne devriez pas économiser sur l’espace disque. Pour cette raison, il est préférable d’utiliser le type INTEGER pour stocker des valeurs entières.

Le domaine d’application des types entiers est évident : ils sont nécessaires pour les champs contenant uniquement des entiers - pour stocker des compteurs, des numéros, etc. En général, le type INTEGER est également utilisé pour les champs contenant des clés primaires.

Types de données réels

Les types FLOAT et DOUBLE PRECISION se rapportent aux types réels (ils sont également appelés types numériques à virgule flottante). Tout d’abord, je veux avertir le lecteur contre l’utilisation du type FLOAT - sa précision n’est pas suffisante pour stocker la plupart des valeurs fractionnaires. Il est particulièrement déconseillé d’y stocker des valeurs monétaires - dans les variables de type FLOAT, des erreurs d’arrondi apparaissent très rapidement et cela peut surprendre un comptable lors de calculs. La meilleure façon de stocker des nombres à virgule flottante (par exemple, dans les systèmes comptables et les systèmes de calculs scientifiques) dans une base de données est de les stocker dans le type DOUBLE PRECISION.

Vous devez prendre en compte que dans le 3e dialecte d’InterBase, il existe un mécanisme de stockage des types à point fixe de 64 octets. Ce mécanisme est utilisé pour stocker des valeurs monétaires. L’utilisation de ces types offre la meilleure précision.

Types de données à point fixe

NUMERIC et DECIMAL se réfèrent à ces types de données. La question de la différence entre NUMERIC et DECIMAL est très fréquente. Ces deux types ont une capacité de chiffres identique - de 1 à 18 signes, une précision identique - de zéro à une capacité de chiffres.

Rappelons que : la capacité de chiffres est le nombre total de chiffres, et la précision - un nombre de signes après la virgule.

Le plus drôle est que ces types diffèrent dans la capacité de chiffres maximale selon la documentation, mais en réalité, ils sont réalisés pratiquement de la même manière et il n’y a aucune différence entre eux.

Vous pouvez facilement le vérifier en démarrant l’utilitaire isql et en effectuant la séquence d’actions ci-dessous. Nous créons la table de la vue suivante :

SQL> CREATE TABLE test (

CON> Num_field NUMERIC(15,2),

CON> Dec_field DECIMAL(15,2));

Ensuite, nous donnons une commande pour afficher la structure de la table :

SQL> show tables test;

Et nous voyons ce qui suit

NUM_FIELD NUMERIC(15, 2) Nullable

DEC_FIELD NUMERIC(15, 2) Nullable

Comme vous pouvez le voir, InterBase informe que les deux colonnes données ont le type NUMERIC. Les raisons d’un tel comportement résident dans la réalisation des types de données à point fixe. Le fait est qu’InterBase n’a que trois mécanismes pour stocker toute expression entière, et tous les types, quel que soit leur nom, sont réalisés selon ces variantes.

Voici le tableau de [1., qui illustre comment divers types entiers (tableau 1.1) sont stockés. Comme vous pouvez le voir, le stockage des données dans le 3e dialecte est différent pour les nombres à grande capacité de chiffres :

Tableau 1.1. Stockage des nombres à point fixe

Capacité de chiffres Dialecte 1 Dialecte 3
de 1 à 4 SMALLINT pour NUMERIC
INTEGER pour DECIMAL
SMALLINT
de 5 à 9 INTEGER INTEGER
de 10 à 18 DOUBLE PRECISION INT64

Maintenant, nous pouvons dire avec certitude quelles sont les principales différences entre les types NUMERIC et DECIMAL : dans le cas de la définition d’un champ (ou d’une variable) avec une petite capacité de chiffres (jusqu’à quatre), le premier est stocké comme un entier SMALLINT de 2 octets, et le second - comme un INTEGER de 4 octets. Ainsi, si une capacité de chiffres est supérieure à quatre, les types DECIMAL et NUMERIC seront équivalents.

Faites attention à la différence de réalisation des types à grande capacité de chiffres dans les premier et troisième dialectes. Dans le premier dialecte, le nombre à point fixe est passé d’entier à réel, où les mécanismes d’arrondi étaient appliqués. Dans le troisième dialecte, cette particularité a été éliminée - les grands entiers sont réellement stockés comme des entiers - en utilisant le mécanisme INT64 qui peut stocker des nombres 64 bits dans une plage de +/-2^32. Par conséquent, il serait préférable de stocker les données sur les fonds monétaires dans les bases de données créées avec l’utilisation du 3e dialecte. Seule l’utilisation du mécanisme INT64 garantira la sécurité des petits restes monétaires.

Types pour stocker la date et l’heure

Les types pour stocker la date et l’heure ont changé dans la version InterBase 6.x et ses clones par rapport aux versions 4.x et 5.x. Afin de ne pas être confus dans les toiles d’araignée historiques avec ces types, nous examinerons une situation dans la version 6 d’InterBase. Ensuite, sur cette base, nous mentionnerons brièvement ce qui existait auparavant. Cela est fait pour les utilisateurs qui travaillent encore avec les premières versions d’InterBase. Ainsi, il existe 3 types dans InterBase 6.x pour stocker la date et l’heure - DATE, TIME et TIMESTAMP.

  • Le type DATE stocke les dates à un jour près. Une plage de valeurs possibles - du 1er janvier 100 apr. J.-C. au 29 février 32768.
  • Le type TIME stocke les données sur l’heure à un dix-millième de seconde près. Une plage de valeurs possibles - de 00:00 à 23:59.9999.
  • Le type TIMESTAMP représente une combinaison des types DATE et TIME.

Comment travailler avec les dates ? S’il s’agit de travailler au niveau du serveur dans des procédures stockées ou des déclencheurs, tout est assez simple - nous pouvons toujours déclarer une variable du type requis et la définir à partir des tables et vice versa. Cependant, il est nécessaire de transférer les données d’une base de données à l’application et inversement. Dans ce cas, il existe deux approches : utiliser des bibliothèques qui appliquent un format original des dates InterBase pour accéder aux objets de ces types et convertir ce format en types de date/heure intralangage ordinaires (FIBPlus est un exemple de telle bibliothèque), ou utiliser le mécanisme de transformation des dates en chaînes, intégré dans InterBase.

Que ferez-vous si vous avez besoin d’extraire uniquement l’année ou le mois d’une date complète ? Vous devrez utiliser un groupe de fonctions EXTRACT à cette fin (disponibles dans tous les clones d’InterBase 6.x) qui vous permettent d’extraire uniquement la partie requise de la date. Ces fonctions sont utilisées de la manière suivante :

EXTRACT (MONTH FROM DATE_FIELD)

EXTRACT (YEAR FROM DATE_FIELD)

La liste complète des paramètres de la fonction EXTRACT est la suivante : YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, WEEKDAY, YEARDAY. Leur fonction découle de leur nom, nous ne les interpréterons donc pas ici.

Types de données pour stocker du texte

Il existe deux types dans InterBase destinés à stocker des informations textuelles - CHAR et VARCHAR. Leurs noms complets - CHARACTER et CHARACTER VARYING, cependant il n’y a aucune raison d’utiliser les noms longs - même la commande Show tables de l’utilitaire isql donne des noms abrégés des types.

Afin de définir un champ ou une variable de type symbolique, il est nécessaire de spécifier entre parenthèses après un nom de type un nombre de symboles qui sera utilisé dans un objet défini, ou d’omettre un nombre de symboles - ainsi le champ avec une longueur de 1 symbole sera créé.

CREATE TABLE testCHARLen(

Field1 CHAR(255),

Field2 CHAR);

Lorsque cette table est créée, Field1 aura une longueur de 255 symboles, et Field2 - 1 symbole.

Les types CHAR et VARCHAR sont à bien des égards similaires - les deux peuvent contenir jusqu’à 32768 symboles, cependant il existe quelques différences. Bien que ces deux types soient stockés dans une base de données de la même manière, InterBase travaille avec eux de manières différentes. L’exemple suivant le démontre :

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 résultat, nous obtiendrons ce qui suit :

(Test ) (Test)

Comme vous pouvez le voir, après la valeur ‘Test’, choisie dans un champ c1, il y avait des espaces. Cela signifie que lors de la sélection des données d’un champ de type CHAR, la valeur retournée est complétée par des espaces jusqu’à la longueur complète du champ. Il est difficile de supposer pourquoi un tel comportement qui conduit à une croissance substantielle du trafic réseau (charge du réseau) est nécessaire. En tout cas, VARCHAR est un type symbolique recommandé à utiliser.

L’une des caractéristiques majeures du type symbolique est son jeu de caractères - CHARACTER SET. Le jeu de caractères est défini pour toute la base de données et utilisé par défaut pour tous les champs symboliques s’il n’est pas redéfini explicitement lors de la création d’un champ. Afin de créer un champ symbolique avec l’indication explicite d’un jeu de caractères, il est nécessaire d’ajouter la description d’un jeu de caractères dans la description d’une colonne (dans les phrases CREATE TABLE ou ALTER TABLE). Le jeu de caractères WIN1251 est généralement utilisé pour le support du russe (si vous voulez savoir en détail sur l’utilisation du russe dans InterBase, voir le chapitre « Russification d’InterBase » (partie 1)). Voici un exemple de table contenant un champ symbolique avec le jeu de caractères WIN1251 explicitement décrit :

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.