Индексы быстрого приготовления
*******************************************************************
* Индексы быстрого приготовления *
* *
* 1. Назначение *
* Нередко возникает задача создания сложного индекса, содержащего *
* поля таблицы разных типов. В общем случае эта задача не имеет *
* однозначного решения, зато в ней имеются забавные подвохи. *
* Предлагаемое решение позволяет строить индексы, даже не *
* зная типов используемых переменных и полей таблицы. Плюс *
* произвольно назначать нарастание/убывание для любого поля, *
* входящего в индекс. При желании можно оптимизировать исходные *
* функции для собственных целей. Для маломерных таблиц *
* оптимизация и не потребуется. *
* *
* 2. Структура программы *
* 2.1. Создаются вспомогательные константы. *
* 2.2. Синтезируется тестовая таблица на 100 000 записей, *
* заполненная случайными значениями. *
* 2.3. Таблица индексируется. *
* 2.4. Индексированная таблица копируется во вторую таблицу для *
* удобства просмотра. *
* 2.5. Тестовые файлы и папка удаляются. *
* *
* 3. Прочее *
* 3.1. Предусмотрена работа под FoxPRO 2...8 *
* *
* 4. Благодарности принимаютсяна ник GoodMan *
* *
* *
******************** 13 апреля 2004 *******************************
SET CENTURY ON
SET TALK OFF
SET ECHO OFF
SET DATE ANSI
SET HOURS TO 24
SET BLOCKSIZE TO 64
SET PROCEDURE TO myindex
PUBLIC records_in_sample
records_in_sample=100000 && число записей в тестовой таблице
DO dbfsample && изготовление тестовой таблицы
DO charset && подготовка вспомогательных символьных констант
SET DEFAULT TO C:_myindex
SELECT 1
INDEX ON (descend1("char_1")+ascend1("logic_1")+descend1("numer_1"));
;
TO myindex.cdx COMPACT
COPY TO dbf2
SELECT 2
USE dbf2
CLEAR
BROWSE LAST
DO goodby && удаление тестовых файлов и папки C:_MYINDEX
*QUIT
*--ASCEND1***********************************
* преобразование аргумента в текстовую *
* константу с характеристикой ASCENDING *
*********************************************
FUNCTION ascend1
PARAMETER cur_obj
PRIVATE cur_obj, obj_type, obj_value
obj_type=TYPE(cur_obj)
DO CASE
CASE (obj_type $ "CM") && идентификация аргументов CHAR и MEMO
obj_value=LEFT(ALLTRIM(LEFT(&cur_obj,254)),20)
CASE (obj_type $ "NY") && идентификация аргументов NUMERIC и CURRENCY
Cur_obj=&cur_obj
DO CASE
CASE cur_obj>0
Obj_value=PADL(STR(LOG(cur_obj)+3000,12,7),12,"0")
CASE cur_obj=0
Obj_value="2000.0000000"
CASE cur_obj<0
Obj_value=PADL(STR(-LOG(-cur_obj)+1000,12,7),12,"0")
ENDCASE
CASE (obj_type $ "D") && идентификация аргументов DATE
Obj_value=DTOC(&cur_obj)
CASE (obj_type $ "T") && идентификация аргументов DATETIME
Obj_value=TTOC(&cur_obj)
CASE (obj_type $ "L") && идентификация аргументов LOGICAL
Obj_value= IIF(&cur_obj=.F., "_0_", "_1_")
OTHERWISE
Obj_value=" "
ENDCASE
RETURN obj_value
*--DESCEND1**********************************
* преобразование аргумента в текстовую *
* константу с характеристикой DESCENDING *
*********************************************
PROCEDURE descend1
PARAMETER cur_obj
PRIVATE cur_obj, obj_type, obj_value
obj_type=TYPE(cur_obj)
DO CASE
CASE (obj_type $ "CM") && идентификация аргументов CHAR и MEMO
obj_value=CHRTRAN(LEFT(ALLTRIM(LEFT(&cur_obj,254)),20),char_up,char_down)
CASE (obj_type $ "NY") && идентификация аргументов NUMERIC и CURRENCY
Cur_obj=&cur_obj
DO CASE
CASE cur_obj>0
Obj_value=PADL(STR(-LOG(cur_obj)+1000,12,7),12,"0")
CASE cur_obj=0
Obj_value="2000.0000000"+REPLICATE("0",12)
CASE cur_obj<0
Obj_value=PADL(STR(LOG(-cur_obj)+3000,12,7),12,"0")
ENDCASE
CASE (obj_type $ "D") && идентификация аргументов DATE
Obj_value=CHRTRAN(DTOC(&cur_obj),"0123456789","9876543210")
CASE (obj_type $ "T") && идентификация аргументов DATETIME
Obj_value=CHRTRAN(TTOC(&cur_obj),"0123456789","9876543210")
CASE (obj_type $ "L") && идентификация аргументов LOGICAL
Obj_value= IIF(&cur_obj=.T., "_0_", "_1_")
OTHERWISE
Obj_value=" "
ENDCASE
RETURN obj_value
*--charset ************************************
* изготовление бинарно дополнительных наборов *
* символов (CHR(0)...CHR(255)) и *
* (CHR(255)...CHR(0)) для инверсии текстовых *
* констант *
***********************************************
PROCEDURE charset
PUBLIC char_up, char_down
PRIVATE i2
STORE "" TO char_up, char_down
i2=0
DO WHILE i2 < 256
Char_up=char_up+CHR(i2)
Char_down=char_down+CHR(255-i2)
I2=i2+1
ENDDO
RETURN
*--dbfsample ****************************
* изготовление тестовой таблицы с *
* разнообразными полями и заполнение их *
* случайными значениями *
*****************************************
PROCEDURE dbfsample
! CD C:
! MD C:_myindex
SET DEFAULT TO C:_myindex
PRIVATE i1
SELECT 1
* определим версию FOXa ...
fox_version=VAL(CHRTRAN(VERSION( ), " ABCDEFGHIJKLMNOPQRSTUVWXYZ"+ ;
"abcdefghijklmnopqrstuvwxyz",""))
DO CASE
CASE (fox_version >= 3)
* Делаем тестовую таблицу для VFP 3...8...
CREATE TABLE MYINDEX ;
( logic_1 L( 1), ;
char_1 C( 10), ;
numer_1 N(15,3), ;
curren_1 Y( 8), ;
memo_1 M , ;
date_1 D( 4), ;
datetime_1 T( 8) )
USE C:_myindexmyindex
tmp=RAND(-1)
i1=1
DO WHILE i1 <= records_in_sample
APPEND BLANK
rand_char= REPLICATE(CHR(RAND( )*255.9),20)
REPLACE char_1 WITH rand_char
REPLACE memo_1 WITH rand_char
rand_num=EXP(RAND( )*25-1) * IIF(RAND()<0.5, -1 , 1)
rand_num=IIF(BETWEEN(rand_num,50,100),0,rand_num)
REPLACE numer_1 WITH rand_num
REPLACE curren_1 WITH rand_num
Date_base={^0100-01-02,01:23:45}
REPLACE date_1 WITH (Date_base+RAND( )*1000000*3600*24)
REPLACE datetime_1 WITH (Date_base+RAND( )*1000000*3600*24)
REPLACE logic_1 WITH IIF((RAND( )-0.5)>0, .T., .F.)
i1=i1+1
IF (MOD(i1,10000)=0)
? " "+STR(i1)+" ЗАПИСЕЙ СИНТЕЗИРОВАНО"
ENDIF
ENDDO
* Делаем тестовую таблицу для FPD/FPW 2.0 ... 2.6
CASE (fox_version < 3)
CREATE TABLE MYINDEX ;
( logic_1 L( 1), ;
char_1 C( 10), ;
numer_1 N(15,3), ;
memo_1 M , ;
date_1 D (8) )
USE C:_myindexmyindex
tmp=RAND(-1)
i1=1
DO WHILE i1 <= records_in_sample
APPEND BLANK
rand_char= REPLICATE(CHR(RAND( )*255.9),20)
REPLACE char_1 WITH rand_char
REPLACE memo_1 WITH rand_char
rand_num=EXP(RAND( )*25-1) * IIF(RAND()<0.5, -1 , 1)
rand_num=IIF(BETWEEN(rand_num,50,100),0,rand_num)
REPLACE numer_1 WITH rand_num
SET DATE ANSI
Date_base=CTOD("01.01.01")
Date_base=Date_base+(RAND( )-0.5)*500000
REPLACE date_1 WITH Date_base
REPLACE logic_1 WITH IIF((RAND( )-0.5)>0, .T., .F.)
i1=i1+1
IF (MOD(i1,10000)=0)
? " "+STR(i1)+" ЗАПИСЕЙ СИНТЕЗИРОВАНО"
ENDIF
ENDDO
ENDCASE
FLUSH
CLEAR
@ 20,20 SAY "ВСЕГО "+STR(i1-1)+" ЗАПИСЕЙ В ТАБЛИЦЕ"
WAIT "" timeout 3.0
CLEAR
@ 20,20 SAY "ТАБЛИЦА ИНДЕКСИРУЕТСЯ . . ."
RETURN
*--goodby *******************************
* чистим тестовые файлы и папки *
*****************************************
PROCEDURE goodby
CLOSE ALL
CLEAR ALL
! DEL C:_myindex*.dbf
! DEL C:_myindex*.fpt
! DEL C:_myindex*.cdx
! RD C:_myindex
RETURN