Унікальні ідентифікатори в access, access, статті, програмування - програмування c, delphi,

В чому проблема
ms access не надає нам можливості вибору способу унікальної ідентифікації рядків таблиць. Єдиний варіант - лічильник. Правда, треба віддати йому належне - в переважній більшості випадків цього достатньо.

Труднощі починаються, коли потрібно консолідувати дані з різних баз. Очевидно, що навіть використання лічильників з випадковими значеннями не гарантує відсутності конфліктів. Вирішувати такі ситуації не просто, головним чином, через те, що в них втягуються крім однієї головної ще й маса підлеглих таблиць. При реплікації також виникають подібні труднощі.

Інший неприємною особливістю лічильника явлалась те, що іноді значення все ж дублюються, особливо при відсутності унікального індексу для такого поля.

способи вирішення
Традиційний метод генерації унікального значення грунтується на створенні спеціальної таблиці з полем, яке змінюється за заданим алгоритмом при кожному новому зверненні до нього клієнтських додатків. З отриманим таким чином значенням можна провести ще якісь маніпуляції і записати в ключове поле. Недоліком способу є його явна трудомісткість і сумнівна надійність. Зокрема, функцію, яка використовується для отримання такого унікального ідентифікатора, не можна використовувати у властивості "Значення за замовчуванням" поля таблиці.

Іншим методом є виділення діапазонів лічильника для кожної з баз. Такий спосіб дуже навіть не поганий. Недоліком можна вважати необхідність заздалегідь планувати кількість і розмір діапазонів. Інакше, кому-то може просто не вистачити номерів. Крім того, установка початкових значень лічильників все ж вимагає додаткових дій.

Третій підхід має на увазі створення вираження, результатом якого було б значення, відповідне для використання в якості унікального ідентифікатора. Також потрібно можливість вказати цей вислів у властивості "Значення за замовчуванням" поля таблиці. Нижче докладно описані два таких вирази: одне строкового, а інше числового типу.

Ідентифікатор типу string
Отримання унікального значення в даному випадку грунтується на генерації рядки з 16-ти символів. Першим йде найлівіший з аргументів командного рядка. Значення командного рядка можна задати не тільки в параметрі запуску / cmd, а й з програми:

application.setoption "command-line arguments", "w"

За ним слідують шістнадцяткові значення поточної дати і часу. Решта 7 символів займає випадкове число (також в шістнадцятковому форматі). У підсумку виходить наступне:

id = left (command (), 1) hex (now () mod 2 ^ 16) hex ((now () - int (now ())) * 65535) hex (rnd () * (2 ^ 28-1))

left (command (), 1) будь-який відповідний символ (повинен бути першим у аргументі командного рядка)
hex (now () mod 2 ^ 16) дата по модулю 65536 (щоб було не більше 4 символів)
hex ((now () - int (now ())) * 65535) час масштабувати до 65535 (щоб було не більше 4 символів)
hex (rnd () * (2 ^ 28-1)) випадкове число в діапазоні від 0 до 2 ^ 28-1 (щоб було не більше 7 символів)

При такому способі, кількість клієнтів в системі обмежена числом допустимих символів для першого (лівого) байти в рядку. Безумовно, таких знайдеться не менше сотні. Якщо потрібно більше, то можна збільшити кількість початкових символів. Розмір ідентифікатора при цьому, зрозуміло, теж зросте. Додатковим плюсом є те, що такий ідентифікатор можна без всяких переробок використовувати в якості ключа для treeview.

Ідентифікатор типу currency
Цей спосіб створення унікального ідентифікатора є розвитком попереднього. Він дозволяє вдвічі зменшити розмір поля і прискорити всі операції з ним, так як робота з числами відбувається швидше, ніж з рядками. Функція виходить, правда, більш громіздка:

id = iif (val (command ())> 63, 1, -1) * (ccur (abs (val (command ()) - 64) * (2 ^ 57) / 10000) + ccur (ccur ((int ( now ()) mod 2 ^ 15) * (2 ^ 42) / 10000) + ccur (((now () - int (now ())) * 65535) * (2 ^ 26) / 10000) + ccur (rnd () * (2 ^ 26 - 1)) / 10000))


Аргумент командного рядка (то, що стоїть за / cmd) повинен бути числом в діапазоні від 1 до 127. Саме стільки клієнтів може бути в системі, що використовує цей спосіб генерації унікального ідентифікатора. Присвоїти цього аргументу значення, наприклад, 127 можна за допомогою такої команди:

application.setoption "command-line arguments", "127"


Число типу currency лежить в діапазоні від - (2 ^ 63) / 10000 до (2 ^ 63-1) / 10000. Тому весь час доводиться ділити на 10000 і перетворювати проміжні результати до типу currency, оскільки access постійно норовить використовувати double. Якщо уявити значення типу currency як ціле число, то використання його розрядів виглядає наступним чином:

Біти Використання в ідентифікатор
Старший 63-й Знак (з аргументу командного рядка)
6 (з 57-го по 62-й) Номер (з аргументу командного рядка)
15 (з 42-го по 56-й) Дата
16 (з 26-го по 41-й) Час
Молодші 26 (з 0-го по 25-й) Випадкове число


Знак числа (більша або менша половина номерів)

iif (val (command ())> 63, 1, -1)


Номер з меншою (1. 63) або більшою (64. 127) половин. Щоб уміститися в тип currency, номер не повинен перевищувати 63. Через це використана функція abs.

ccur (abs (val (command ()) - 64) * (2 ^ 57) / 10000)


Дата. Розподіл по модулю 2 ^ 15 дозволяє втиснутися в відведені 15 біт, зберігаючи унікальність при цьому близько 80 років.

ccur (ccur ((int (now ()) mod 2 ^ 15) * (2 ^ 42) / 10000)


Час з точністю до

1,3 секунди. У проміжку від 00:00:00 до 23:59:59 приймає значення від 0 до 0,99999 і масштабується до потрібних 16 біт множенням на 65535.

ccur (((now () - int (now ())) * 65535) * (2 ^ 26) / 10000)


Випадкове число в діапазоні від 0 до 2 ^ 26 - 1. Зменшення діапазону призводить до виникнення повторів.

ccur (rnd () * (2 ^ 26 - 1)) / 10000))


висновок
Другий спосіб, очевидно, є більш привабливим, тому що дозволяє створювати більш компактні ідентифікатори. Крім того, він дозволяє відносно безболісно перейти від використання лічильників, так як робота з рядками набагато сильніше відрізняється від роботи з типами long або currency, чим вони відрізняються один від одного.

Однак, є і недоліки. Перш за все, це обмежена кількість клієнтів в системі (не більше 127), викликане складністю втиснутися в рамки 8-ми байтного числа. Також, немає повної гарантії, що випадкові числа не повторяться в межах тих 1,3 секунди, коли унікальність ключа визначається виключно роботою генератора випадкових чисел. У разі такого повтору виникне помилка дублювання, яка зажадає повтору всієї операції додавання записів. Правда, треба віддати належне access'совской функції rnd (): вона досить довго генерує неповторяющийся потік значень.