이 페이지는 기계 번역되었습니다. 영어 원본을 읽어보세요. English

IBSurgeon 라이브러리

데이터 유형

NOTICE: This document is the chapter from the book “The InterBase World” which was written by Alexey Kovyazin and Serg Vostrikov.

Несмотря на то, что типы данных подробно описаны в документации (см. [1, глава 4.), необходимо рассмотреть ряд понятий, которые будут часто использоваться в следующих главах этой книги. Помимо общей информации, будут также рассмотрены несколько примеров использования типов данных в базах данных InterBase и рекомендации по их использованию и преобразованию. Мы подробно рассмотрим различия типов данных, существующие в 1-м и 3-м диалектах базы данных InterBase.

О данных

Типы данных являются базовыми элементами любого языка программирования или любого сервера СУБД. InterBase не является исключением. Когда мы говорим, что база данных хранит некоторую информацию, мы должны понимать, что эта информация не может храниться в одном месте. Наоборот, данные должны быть рассортированы и разложены по своим «полкам». Типы данных определяют, что можно положить на определенную «полку», а что нельзя. Когда мы говорим о «полке», прежде всего мы имеем в виду поля таблиц базы данных (см. главу «Таблицы. Первичные ключи и генераторы» (часть 1)), а также переменные внутри триггеров и хранимых процедур и т.д. Каждый тип данных имеет набор операций, которые могут выполняться над значениями этого типа. Поэтому важно правильно выбрать тип данных при проектировании базы данных. Это поможет избежать многих проблем при разработке клиентских программ. В InterBase есть 12 типов данных, которые могут удовлетворить требования разработчика по хранению данных. Эти типы условно подразделяются на следующие 6 групп:

  • для хранения целых чисел - INTEGER и SMALLINT;
  • для хранения вещественных чисел - FLOAT и DOUBLE PRECISION;
  • для хранения чисел с фиксированной точностью - NUMERIC и DECIMAL;
  • для хранения даты, времени и метки времени - DATE, TIME и TIMESTAMP;
  • для хранения символов - CHARACTER (в сокращенной форме - CHAR) и VARYING CHARACTER (VARCHAR);
  • для хранения динамически расширяемых данных - BLOB

Кроме того, можно определять массивы значений примитивных типов, т.е. всех перечисленных типов, кроме BLOB.

Большинство типов данных InterBase соответствуют типам, определенным в стандарте SQL92, однако, помимо этого, есть свои особенности - массивы примитивных типов данных и BLOB. Массивы в InterBase могут содержать набор данных одного типа в одном поле. Например, можно определить массив значений типа INTEGER. Массивы могут иметь несколько измерений. Тип данных BLOB - это динамически расширяемый тип данных, название которого часто расшифровывается как Binary Large OBject. Следует сказать, что BLOB - это изобретение разработчиков InterBase, которое позже распространилось и закрепилось во всех современных SQL-серверах.

Синтаксис определения типов данных

Типы данных используются для описания полей в таблицах, переменных в триггерах и хранимых процедурах. Общий синтаксис определения всех возможных типов данных в InterBase приведен ниже.

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

Характеристики типов данных, такие как размер, точность и диапазон возможных значений, подробно описаны в таблице 4.1 в [1., поэтому мы не будем повторяться. Теперь кратко рассмотрим основные особенности типов данных и сосредоточимся на их возможном применении.

Целочисленные типы

SMALLINT и INTEGER относятся к целочисленным типам. Следует сказать, что SMALLINT представляет собой урезанную версию INTEGER. Его длина составляет 2 байта, в отличие от 4, предназначенных для хранения INTEGER. Обычно не следует экономить на дисковом пространстве. По этой причине для хранения целочисленных значений лучше использовать тип INTEGER.

Область применения целочисленных типов очевидна: они необходимы для полей, содержащих только целые числа - для хранения счетчиков, номеров и т.д. Обычно тип INTEGER также имеют поля, содержащие первичные ключи.

Вещественные типы данных

Типы FLOAT и DOUBLE PRECISION относятся к вещественным (их также называют числами с плавающей точкой). Прежде всего, я хочу предостеречь читателя от использования типа FLOAT - его точности недостаточно для хранения большинства дробных значений. Особенно не рекомендуется хранить в нем денежные значения - в переменных типа FLOAT ошибки округления появляются очень быстро, и это может удивить бухгалтера при расчетах. Лучший способ хранения чисел с плавающей точкой (например, в бухгалтерских системах и системах для научных расчетов) в базе данных - хранить их в типе DOUBLE PRECISION.

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

Типы данных с фиксированной точкой

К этим типам данных относятся NUMERIC и DECIMAL. Вопрос о различии между NUMERIC и DECIMAL звучит очень часто. Оба этих типа имеют одинаковую разрядность - от 1 до 18 знаков, одинаковую точность - от нуля до разрядности.

Напомним, что: разрядность - это общее количество цифр, а точность - количество знаков после запятой.

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

Вы легко можете проверить это, запустив утилиту isql и выполнив нижеописанную последовательность действий. Создадим таблицу следующего вида:

SQL> CREATE TABLE test (

CON> Num_field NUMERIC(15,2),

CON> Dec_field DECIMAL(15,2));

Затем дадим команду показать структуру таблицы:

SQL> show tables test;

И мы видим следующее:

NUM_FIELD NUMERIC(15, 2) Nullable

DEC_FIELD NUMERIC(15, 2) Nullable

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

Вот таблица из [1., которая иллюстрирует, как хранятся различные целочисленные типы (таблица 1.1). Как вы можете видеть, хранение данных в 3-м диалекте отличается для чисел с большой разрядностью:

Таблица 1.1. Хранение чисел с фиксированной точкой

Разрядность Диалект 1 Диалект 3
от 1 до 4 SMALLINT для NUMERIC
INTEGER для DECIMAL
SMALLINT
от 5 до 9 INTEGER INTEGER
от 10 до 18 DOUBLE PRECISION INT64

Теперь мы можем точно сказать, в чем основные различия между типами NUMERIC и DECIMAL: в случае определения поля (или переменной) с малой разрядностью (до четырех) первое хранится как 2-байтовое целое SMALLINT, а второе - как 4-байтовое INTEGER. Таким образом, если разрядность больше четырех, типы DECIMAL и NUMERIC будут эквивалентны.

Обратите внимание на разницу в реализации типов с большой разрядностью в первом и третьем диалектах. В первом диалекте число с фиксированной точкой превращалось из целого в вещественное, где применялись механизмы округления. В третьем диалекте эта особенность была устранена - большие целые числа хранятся действительно как целые - с использованием механизма INT64, который может хранить 64-битные числа в диапазоне +/-2^32. Поэтому лучше хранить данные о денежных средствах в базах данных, созданных с использованием 3-го диалекта. Только использование механизма INT64 гарантирует сохранность небольших денежных остатков.

날짜 및 시간 저장을 위한 타입

날짜와 시간을 저장하기 위한 타입은 InterBase 6.x 및 그 클론 버전에서 4.x 및 5.x 버전과 비교하여 변경되었습니다. 이러한 타입에 대한 역사적 혼란을 피하기 위해 InterBase 6버전의 상황을 살펴보겠습니다. 그런 다음 이를 기반으로 이전 버전에 대해 간략히 언급하겠습니다. 이는 여전히 초기 버전의 InterBase를 사용하여 작업하는 사용자들을 위한 것입니다. InterBase 6.x에는 날짜와 시간을 저장하기 위한 3가지 타입(DATE, TIME 및 TIMESTAMP)이 있습니다.

  • DATE 타입은 날짜를 하루 단위로 저장합니다. 가능한 값의 범위는 서기 100년 1월 1일부터 32768년 2월 29일까지입니다.
  • TIME 타입은 시간을 1만분의 1초 단위로 저장합니다. 가능한 값의 범위는 00:00 AM부터 23:59.9999 PM까지입니다.
  • TIMESTAMP 타입은 DATE와 TIME 타입의 조합을 나타냅니다.

날짜로 작업하는 방법은 무엇일까요? 저장 프로시저나 트리거에서 서버 수준에서 작업하는 경우라면 모든 것이 매우 간단합니다. 필요한 타입의 변수를 선언하고 테이블에서 값을 가져오거나 그 반대로 설정할 수 있습니다. 그러나 데이터를 데이터베이스에서 애플리케이션으로 또는 그 반대로 전송해야 합니다. 이 경우 두 가지 접근 방식이 있습니다: InterBase 날짜의 원래 형식을 적용하는 라이브러리를 사용하여 이러한 타입의 객체에 접근하고 이 형식을 일반적인 언어 내부 날짜/시간 타입으로 변환하는 방법(FIBPlus가 그러한 라이브러리의 예입니다), 또는 InterBase에 내장된 날짜를 문자열로 변환하는 메커니즘을 사용하는 방법입니다.

전체 날짜에서 연도나 월만 추출해야 한다면 어떻게 하시겠습니까? 이를 위해 InterBase 6.x의 모든 클론에서 사용 가능한 EXTRACT 함수 그룹을 사용해야 하며, 이를 통해 날짜에서 필요한 부분만 추출할 수 있습니다. 이러한 함수는 다음과 같은 방식으로 사용됩니다:

EXTRACT (MONTH FROM DATE_FIELD)

EXTRACT (YEAR FROM DATE_FIELD)

EXTRACT 함수의 전체 매개변수 목록은 다음과 같습니다: YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, WEEKDAY, YEARDAY. 그 기능은 이름에서 알 수 있으므로 여기서 자세히 설명하지 않겠습니다.

텍스트 저장을 위한 데이터 타입

InterBase에는 텍스트 정보를 저장하기 위한 두 가지 타입(CHAR 및 VARCHAR)이 있습니다. 전체 이름은 CHARACTER 및 CHARACTER VARYING이지만 긴 이름을 사용할 이유가 없습니다. isql 유틸리티의 Show tables 명령조차도 간단한 타입 이름을 제공합니다.

기호 타입의 필드나 변수를 정의하려면 타입 이름 뒤의 괄호 안에 정의된 객체에서 사용될 기호 수를 지정하거나 기호 수를 생략해야 합니다. 이 경우 길이가 1기호인 필드가 생성됩니다.

CREATE TABLE testCHARLen(

Field1 CHAR(255),

Field2 CHAR);

이 테이블이 생성되면 Field1의 길이는 255기호이고 Field2는 1기호가 됩니다.

CHAR 및 VARCHAR 타입은 여러 면에서 유사합니다. 둘 다 최대 32768기호를 포함할 수 있지만 몇 가지 차이점이 있습니다. 이 두 타입 모두 데이터베이스에 동일한 방식으로 저장되지만 InterBase는 이들을 다르게 처리합니다. 다음 예제는 이를 보여줍니다:

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;

결과적으로 다음과 같은 결과를 얻을 수 있습니다:

(Test ) (Test)

보시다시피 c1 필드에서 선택된 값 ‘Test’ 뒤에는 공백이 있습니다. 이는 CHAR 타입의 필드에서 데이터를 선택할 때 반환된 값이 필드의 전체 길이까지 공백으로 채워진다는 것을 의미합니다. 네트워크 트래픽(네트워크 부하)의 상당한 증가로 이어지는 이러한 동작이 왜 필요한지 추측하기는 어렵습니다. 어쨌든 VARCHAR는 사용을 권장하는 기호 타입입니다.

기호 타입의 주요 특성 중 하나는 문자 집합(CHARACTER SET)입니다. 문자 집합은 데이터베이스 전체에 대해 정의되며 필드 생성 시 명시적으로 재정의되지 않는 한 모든 기호 필드에 기본적으로 사용됩니다. 문자 집합을 명시적으로 표시하여 기호 필드를 생성하려면 열 설명(CREATE TABLE 또는 ALTER TABLE 문)에 문자 집합 설명을 추가해야 합니다. 러시아어 지원을 위해 일반적으로 WIN1251 문자 집합이 사용됩니다(InterBase에서 러시아어 사용에 대해 자세히 알아보려면 “InterBase Russification”(1부) 장을 참조하십시오). 다음은 문자 집합 WIN1251이 명시적으로 설명된 기호 필드를 포함하는 테이블의 예입니다:

CREATE TABLE TestCHARSET(

Field1 VARCHAR(255),

Field2 VARCHAR(255) CHARACTER SET win1251);

여기서 Field1은 문자 집합이 명시적으로 표시되지 않은 필드이므로 데이터베이스 생성 시 지정된 문자 집합이 사용됩니다. Field2의 경우 WIN1251 코딩으로 기호를 저장할 것이 분명하게 결정됩니다.

기호 필드에 대한 문자 집합을 지정하는 것 외에도 이 데이터 집합의 기호가 정렬되는 방식을 정의하는 콜레이션 순서(collation order)를 지정할 수도 있습니다. 러시아어에는 WIN1251 및 PXW_CYRL의 두 가지 콜레이션 변형이 있습니다. COLLATION ORDER 사용에 대한 자세한 내용은 “InterBase Russification” 장을 참조하십시오.

적용된 문자 집합 및 COLLATION ORDER의 전체 목록은 문서 [1, 13장]에서 찾을 수 있습니다.

주의! InterBase 6 문서에 따르면 4가지 기호 타입이 있습니다: 위에서 언급한 데이터 타입 외에 NCHAR 및 NCHAR VARYING의 2가지가 더 존재하지만, 같은 문서의 아래 부분에서는 마지막 두 타입이 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 database structure” (4부) 장 참조)에 서로 가깝게 위치하지만, BLOB 식별자만 데이터 페이지에 저장되고 BLOB 자체는 특수 페이지에 할당됩니다. 이러한 데이터 구조는 고정되지 않은 크기의 데이터를 저장할 수 있게 합니다.

BLOB 타입은 여러 하위 타입 집합과 이러한 하위 타입 작업을 위한 필터(BLOB 필터)라는 특수 프로시저를 정의할 수 있는 기능이 있습니다. InterBase에는 미리 정의된 몇 가지 BLOB 하위 타입이 내장되어 있습니다. 이러한 모든 하위 타입은 음수가 아닌 숫자를 가지며, 예를 들어 하위 타입 0은 정의되지 않은 타입의 데이터, 하위 타입 1은 텍스트, 하위 타입 2는 BLR(Binary Language Representation, 용어집 및 “InterBase database structure” 장 참조) 등입니다. 사용자는 음수 값을 가질 수 있는 BLOB 하위 타입도 정의할 수 있습니다. 필터는 모든 타입에 적용할 수 있습니다. 필터는 한 하위 타입의 필드를 다른 하위 타입으로 변환합니다.

BLOB 필드 사용은 일반적으로 데이터베이스와 관련된 외부 파일 저장의 대안이라는 점에 유의해야 합니다. BLOB 필터의 경우 좁은 범주의 작업에 맞춰져 있기 때문에 사용되는 경우가 매우 드뭅니다.

배열

InterBase DBMS는 배열이 등장한 최초의 제품 중 하나였습니다. 데이터베이스에서 배열 지원은 전통적인 관계형 모델의 확장입니다. 배열의 존재는 하나의 데이터 타입 집합으로 작업을 단순화할 수 있게 합니다.

배열은 한 가지 유형의 값들의 모음으로, 공통된 이름을 가지며 번호에 따라 배열의 모든 요소에 접근할 수 있게 해줍니다. InterBase의 배열은 1차원 및 다차원일 수 있습니다.

테이블에 INTEGER 숫자 배열 필드를 생성하려면 다음과 같이 작성해야 합니다.

CREATE TABLE test(

myOneDimArray INTEGER[12.,

myTwoDimArray INTEGER[5,4.,

myThreeDimArray INTEGER[2,10,8.);

따라서 세 개의 배열 유형 필드가 생성됩니다: myOneDimArray - 12개 숫자 길이의 1차원 배열을 포함하는 필드, myTwoDimArray - 2차원 배열(행렬) 5x4 정수를 포함하는 필드, myThreeDimArray - 2x10x8의 3차원 배열을 포함하는 필드입니다. 이러한 정의에서 배열 요소는 “1"부터 번호가 매겨진다는 점에 유의해야 합니다. 즉, 첫 번째 요소는 1, 두 번째 요소는 2 등입니다. 배열의 경계를 직접 설정하려는 경우, 예를 들어 0부터 5까지로 설정하려면 필드 정의를 다음과 같이 지정해야 합니다:

myArray INTEGER[0:5.

배열은 BLOB 유형의 필드를 기반으로 구현되므로 다차원 배열이 테이블을 많은 데이터로 “오염"시킬까 걱정할 필요가 없습니다: InterBase는 이러한 필드의 입출력 작업을 최적화하기 위해 배열 데이터를 별도의 페이지에 깔끔하게 할당합니다. 배열을 어떻게 사용할까요? 배열은 동일한 유형의 객체를 저장하는 편리한 메커니즘을 제공합니다. 그러나 80%의 경우 개발자는 배열 대신 여러 데이터를 하위(세부) 테이블에 저장하는 것을 선호하므로 배열은 InterBase DBMS의 클라이언트 응용 프로그램에서 그렇게 자주 사용되지 않습니다. 이는 Delphi 및 C++ Builder와 함께 제공되는 BDE 및 IBX와 같은 액세스 라이브러리가 배열과 함께 작동할 수 없기 때문입니다. InterBase 문서에 따르면 gpre 전처리기를 사용하여 배열로 작업할 수 있지만 이는 Delphi/C++ Builder 개발자에게 가장 편리한 방법은 아닙니다. 다행히 FIBPlus 라이브러리에는 InterBase의 배열 필드 지원이 있습니다. 자세한 내용은 “FIBPlus 특별 기능” 장에서 읽을 수 있습니다. Microsoft 개발 도구를 사용하여 InterBase용 클라이언트 응용 프로그램을 만들 수 있는 클라이언트 라이브러리 IBProvider도 배열 작업을 지원합니다(“Microsoft OLE DB 기술을 사용한 InterBase DBMS 클라이언트 응용 프로그램 개발” 장(3부) 참조).

결론

데이터 유형에 대해 이야기할 때 앞서 나가지 않을 수 없다는 점에 유의해야 합니다. 데이터 유형은 데이터베이스 응용 프로그램 개발과 관련된 모든 핵심 영역에 침투하기 때문입니다. 따라서 이 책을 읽을 때는 이 장을 InterBase의 기초를 새로 고칠 필요가 있을 때마다 참조할 수 있는 빠른 참조 자료로 사용하는 것이 좋습니다.