Извлечение данных
Два следующих фрагмента TDBStatistics очень тесно связаны, поэтому мы постараемся работать над ними одновременно. Первый— процедура проверки ошибок GetRange. Во время извлечения данных компонентом она должна убедиться в том, что все делается «законно». Обычно это сводится к тому, чтобы компонент не пытался читать за последней записью, и т. д.
Однако в случае TDBStatistics все оказывается несколько сложнее. Так как пользователь может захотеть проанализировать набор записей, превышающий границы нашего массива, мы должны позволить ему выбрать подмножество данных. Для этого используются два свойства: UpperBound и LowerBound. Они предоставляют компоненту информацию о начальной и конечной записях набора. Следовательно, процедура проверки должна следить за этими двумя величинами. Самый простой выход заключается в использовании функции, которая:
- Проверяет правильность свойств;
- Вносит необходимые поправки;
- Возвращает разность (с учетом поправок) между UpperBound и LowerBound.
Прежде всего мы проверяем, что значение LowerBound положительно, а UpperBound не меньше, чем
LowerBound + 1: if (LowerBound < 1) then LowerBound := 1; if (UpperBound < 1) then UpperBound := LowerBound + 1;ALIGN="JUSTIFY">Следующая проверка убеждает в том, что UpperBound больше, чем LowBound. Если выясняется обратное, значения LowBound и UpperBound меняются местами:
if (LowerBound > UpperBound) then begin TempInt := UpperBound; UpperBound := LowerBound; LowerBound := TempInt; end;Затем мы проверяем, не превышают ли UpperBound и LowerBound количество записей в источнике (то есть значение DataSource.DataSet.RecordCount, извлечен ное ранее и сохраненное в переменной Records), и при необходимости исправляем их:
if (LowerBound > Records) then LowerBound := 1; if (UpperBound > Records) then UpperBound := Records;При последней проверке мы убеждаемся в том, что разность между UpperBound и LowerBound не превышает количества элементов в массиве Data. Другими словами, количество сохраняемых элементов не должно превышать размер массива:
if (UpperBound - LowerBound > MaxValues) then UpperBound := LowerBound + MaxValues;Наконец, функция GetRange возвращает разность между проверенными и исправленными значениями
UpperBound и LowerBound: Result := UpperBound - LowerBound;Так в нашем случае выполняется проверка ошибок.
После завершения проверки можно переходить к извлечению данных из источника и их сохранению в массиве Data. Это происходит в процедуре FillArray.
Настоящая работа FillArray начинается с вызова GetRange. Затем, после проверки границ (см. выше), можно извлечь данные и сохранить их в локальном массиве. Сначала мы открываем источник данных и переходим к записи, номер которой задается свойством
LowerBound: fDataSource.DataSet.Open; fDataSource.DataSet.MoveBy(LowerBound);Затем мы проверяем тип fDataField. Если поле содержит числовые значения, мы читаем данные, запись за записью, и помещаем их в массив Data:
if ((fDataSource.DataSet.FieldByName(fDataField) is TCurrencyField) or (fDataSource.DataSet.FieldByName(fDataField) is TFloatField) or (fDataSource.DataSet.FieldByName(fDataField) is TIntegerField) or (fDataSource.DataSet.FieldByName(fDataField) is TSmallIntField))then begin for i := LowerBound to UpperBound do begin if not (fDataSource.DataSet.FieldByName (fDataField).IsNull) then Data[Index] := fDataSource.DataSet.FieldByName (fDataField).Value else Data[Index] := 0; Inc(Index); fDataSource.DataSet.Next; end; endИз символьных полей данные извлекаются несколько иначе. Единственный вид символьных данных, с которыми умеет работать наш компонен т, — это ZIP-коды1. Существует два типа ZIP-кодов: старые, состоящие из пяти цифр, и новые, «пять плюс четыре».
С точки зрения TDBStatistics ZIP-коды из пяти цифр можно преобразовать в числовой тип без дальнейшей обработки. Если значение состоит из девяти цифр и включает дефис, то дефис необходимо предварительно заменить символом «точка» (.), чтобы поле можно было привести к числовому типу:
else if (fDataSource.DataSet.FieldByName (fDataField) is TStringField) then begin for i := LowerBound to UpperBound do begin TempString := fDataSource.DataSet.FieldByName (fDataField).Value; if (Pos('-', TempString) > 0) then TempString[Pos('-', TempString)] := '.'; Data[Index] := StrToFloat(TempString); Inc(Index); fDataSource.DataSet.Next; end; end;Наконец, мы закрываем источник данных и сбрасываем два флага:
fDataSource.DataSet.Close;
IsArrayFilled := True;
DidGetAll := False;
Переменная IsArrayFilled позволяет другим методам компонента узнать, были ли извлечены данные из источника. Если она равна False, другие процедуры могут вызвать FillArray перед тем, как начинать свою работу. Переменная DidGetAll — другой флаг, используемый методами доступа (его смысл разъясняется ниже).