Предупреждение: ваш код имеет недостатки в многопользовательской среде. Два человека могут выполнить запрос одновременно и получить один и тот же идентификатор. Один из них завершится с ошибкой INSERT, если у столбца есть первичный ключ или ключ-кандидат, что рекомендуется для ключевых полей.
Я рекомендую, чтобы идентификатор представлял собой целочисленное поле с автоинкрементом (я не фанат этого), или, что еще лучше, создайте таблицу ключей. Каждая запись в таблице предназначена для таблицы, которой назначены ключи. Я использую структуру, подобную этой:
Structure for: countergenerator.dbf
Database Name: conferencereg.dbc
Long table name: countergenerator
Number of records: 0
Last updated: 11/08/2008
Memo file block size: 64
Code Page: 1252
Table Type: Visual FoxPro Table
Field Name Type Size Nulls Next Step Default
----------------------------------------------------------------------------------------------------------------
1 ccountergenerator_pk Character 36 N guid(36)
2 ckey Character (Binary) 50 Y
3 ivalue Integer 4 Y
4 mnote Memo 4 Y "Automatically created"
5 cuserid Character 30 Y
6 tupdated DateTime 8 Y DATETIME()
Index Tags:
1. Tag Name: PRIMARY
- Type: primary
- Key Expression: ccountergenerator_pk
- Filter: (nothing)
- Order: ascending
- Collate Sequence: machine
2. Tag Name: CKEY
- Type: regular
- Key Expression: lower(ckey)
- Filter: (nothing)
- Order: ascending
- Collate Sequence: machine
Теперь код для хранимой процедуры в DBC (или в другой программе) такой:
ФУНКЦИЯ NextCounter (tcAlias)
LOCAL lcAlias,;
lnNextValue,;
lnOldReprocess,;
lnOldArea
lnOldArea = SELECT ()
ЕСЛИ ПАРАМЕТРЫ () <1
lcAlias = ALIAS () </p>
IF CURSORGETPROP ("SOURCETYPE") = DB_SRCLOCALVIEW
* - Попытка получить базовую таблицу
lcAlias = LOWER (CURSORGETPROP ("TABLES"))
lcAlias = SUBSTR (lcAlias, AT ("!", lcAlias) + 1)
ENDIF
ELSE
lcAlias = НИЖНЯЯ (tcAlias)
ENDIF
lnOrderNumber = 0
lnOldReprocess = SET ('REPROCESS')
* - Блокировка, пока пользователь не нажмет Esc
УСТАНОВИТЬ РЕПРОЦЕСС В АВТОМАТИЧЕСКИЙ
ЕСЛИ! ИСПОЛЬЗУЕТСЯ («контргенератор»)
ИСПОЛЬЗУЙТЕ КОНТРОГЕНЕРАТОР EventManagement! В 0 ПРОГРЕССИРОВАННЫЙ АЛИАС
ENDIF
ВЫБРАТЬ контргенератор
IF SEEK (LOWER (lcAlias), «контргенератор», «ключ»)
ЕСЛИ RLOCK ()
lnNextValue = countergenerator.iValue
ЗАМЕНИТЕ countergenerator.iValue НА countergenerator.iValue + 1
ОТКРЫТЬ
ENDIF
ELSE
* Создать новую запись с начальным значением.
APPEND BLANK IN контргенератор
СКАТЕР МЕМВАР МЕМО
m.cKey = LOWER (lcAlias)
m.iValue = 1
m.mNote = "Автоматически создается хранимой процедурой."
m.tUpdated = DATETIME ()
MEMVAR MEMO
IF RLOCK ()
lnNextValue = countergenerator.iValue
ЗАМЕНИТЕ countergenerator.iValue НА countergenerator.iValue + 1
ОТКРЫТЬ
ENDIF
ENDIF
SELECT (lnOldArea)
УСТАНОВИТЬ РЕПРОЦЕСС ДЛЯ LnOldReprocess
RETURN lnNextValue
EndFunc
RLOCK () гарантирует отсутствие конкуренции за записи и является достаточно быстрым, чтобы не допустить узкого места в процессе. Это намного безопаснее, чем тот подход, который вы сейчас используете.
Рик Шуммер
VFP MVP