Унікальні ідентифікатори, MS Office, Програмні керівництва, статті

У чому проблема

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 як ціле число, то використання його розрядів виглядає наступним чином:



























Біти


Використання в ідентифікаторі


Старший шістьдесят третій


Знак (з аргументу командного рядка)


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 (): вона досить довго генерує неповторяющийся потік значень.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*