"Упакованное" хранение
до 32-х стандартных логических полей (Boolean) в
одном числовом поле таблицы
Вынашивал я
одну мыслю - почему при достаточно большом
количестве логических полей в таблице (а их
обычно бывает более двух) не организовать
упаковку в числовое поле? Ведь что такое
числовое поле типа Byte? Это массив из 8 битов,
которые выглядит так:
8 7 6 5 4 3 2 1 -
вот эти биты и составляют число типа Byte.
Обратите внимание - самый младший бит идет
под номером 1, а самый старший под номером 8.
Вот такой обратный отсчет зародится на заре
компьютеростроения, когда даже Биллу
Гейтсу казалось, что 640 Кб (Килобайт!!!) ОЗУ
хватит на всё и больше просто не
потребуется никогда.
А что хранит
логическое поле типа Boolean ? Да только
логическую информацию, типа, да/нет,
включено/выключено, мужчина/женщина ;). Для хранения
такой информации достаточно одного бита,
который принимает состояния 0 и 1
соответственно. То есть, для хранения 8-ми
логических полей достаточно 1 байта, для
хранения 16 - двух байтов, 32 логических полей
- четырех байтов.
Правда, в
справке Access XP указывается, что размер
логического поля 1 бит. Хм.... если значение
True принимает -1, а значение False - 0, то тогда
для хранения информации о данном бите все
равно необходим хотя бы один байт.
Непонятно, чтение литературы по данному
вопросу тоже ничего не прояснило. Буду рад
услышать аргументированное мнение по
данному вопросу.
Логический
|
Значения «Да» и
«Нет», а также поля, содержащие только
одно из двух возможных значений (Да/Нет,
True/False или Вкл/Выкл).
|
1 бит
|
По моему,
тут ошибка в справке заключается в том,
что для хранения логической информации
действительно необходим лишь один бит, но
само-то логическое поле должно занимать,
как минимум, байт. Биты же не могут
храниться отдельно, а только в составе
байта, такова архитектура компьютеров x86.
Мы
рассмотрим возможность хранения до 8
логических полей в одном поле типа Byte (0-255,
занимает 1 байт, во что охотно верится ;).
Вы легко сможете расширить пример и для
хранения до 32 логических полей, которые
будете должны хранить в поле типа Long (0-2147483647,
занимает 4 байта).
В
отдельный модуль вставьте три функции:
Public Function SetBitField(lngValue
As Long, lngFieldNumber As
Long) As Boolean
' установка бита (флага) в указанной позиции
On Error GoTo ErrorLevel
lngValue = lngValue Imp 2 ^ (8 - lngFieldNumber)
lngValue = lngValue Imp 2 ^ (8 - lngFieldNumber)
SetBitField = True
Exit Function
ErrorLevel:
MsgBox Err & ": " & Err.Description
SetBitField = False
End Function
Public Function WipeBitField(lngValue As
Long, lngFieldNumber As Long) As Boolean
' сброс бита (флага) в указанной позиции
On Error GoTo ErrorLevel
lngValue = lngValue And (Not (2 ^ (8 - lngFieldNumber)))
WipeBitField = True
Exit Function
ErrorLevel:
MsgBox Err & ": " & Err.Description
WipeBitField = False
End Function
Public Function CheckBitField(lngValue As
Long, lngFieldNumber As Long) As Boolean
' проверка бита (флага) в указанной позиции
On Error GoTo ErrorLevel
lngValue = lngValue And 2 ^ (8 - lngFieldNumber)
If lngValue <> 2 ^ (8 - lngFieldNumber)
Then
CheckBitField = False
Else
CheckBitField = True
End If
Exit Function
ErrorLevel:
MsgBox Err & ": " & Err.Description
CheckBitField = False
End Function
Затем в модуле формы создадим кнопку и в
событие [Нажатие кнопки] вставляем данный
код:
Private Sub Кнопка0_Click()
Dim bytValueBoolField As Long
On Error GoTo Error_Кнопка0_Click
' 00000000 =
схематическое представление битов
' 12345678 = номера позиций битов
для указания при вызовах функций
bytValueBoolField = 143
' присвоим тестовое значение 10001111 = 143
If Not SetBitField(bytValueBoolField, 2)
Then MsgBox "Бит не хочет устанавливаться"
MsgBox bytValueBoolField
' при установке бита во второй позиции будет число 207 =
11001111
If Not WipeBitField(bytValueBoolField, 1)
Then MsgBox "Бит не хочет сбрасываться"
MsgBox bytValueBoolField
' при сбросе бита в первой позиции будет число 79 =
01001111
MsgBox CheckBitField(bytValueBoolField, 1)
' проверка бита в первой позиции вернет значение False = бит сброшен
Exit Sub
Error_Кнопка0_Click:
MsgBox Err & ": " & Err.Description
End Sub
Теперь в
любой момент можно узнать состояние
любого бита - достаточно передать
требуемой функции два параметра: самое
числовое значение и номер позиции бита.
Обратите внимание: несмотря на то, что
биты считаются компьютером справа налево,
номер позиции передается "нормальным
человеческим языком", то есть считая
слева направо (для этого в функциях есть
необходимое преобразование (8 - lngFieldNumber) ).
Конечно,
если логических полей в таблице два-три,
то может быть возня не стоит свеч ;). Но уже
при количестве полей, приближающихся к 8,
надо будет серьезно задуматься о таком
вот "упакованном" хранении
информации.
Еще одна
идея: если в числовом значении типа Long
хранится 32 бита, то есть 32 отдельных поля,
которые можно рассматривать как массив -
в них можно хранить дни любого месяца,
например: дежурство сотрудника по дням
месяца. В свою очередь, в 8-битном массиве
можно хранить дни недели. Проверку, сброс,
установку всех битов легко организовать
в цикл. При работе с такими массивами
битов полезно будет держать в голове
способы управления битами с помощью
логических операторов And, Eqv, Imp, Not, Or, Xor,
например: инверсия (Not) оптимальна
для переключения состояния всех битов (команда
- инвертировать выделенное).
Преимущества:
индексация для каждого логического поля
не нужна, т.к. логических полей не
существует - выигрыш в размере базы,
вместо 8-32 байтов (логических полей)
используется один-четыре - выигрыш в 7 раз.
Меньше полей - меньше путаницы и
захламления конструктора и таблиц.
Недостатки:
необходимо дополнительное вычисление
для получения результата, необходимо
планирование и документирование
диапазона битов (а где оно не нужно?)
Вывод: при
грамотном подходе можно умело и красиво использовать
данные функции с целью оптимизации
размеров баз.