Форум программистов, компьютерный форум, киберфорум
Наши страницы
MS Access
Войти
Регистрация
Восстановить пароль
Результаты опроса: Есть необходимость создавать свои статьи
согласен (согласна) 6 100.00%
не согласен (не согласна) 0 0%
мне все равно 0 0%
Голосовавшие: 6. Вы ещё не голосовали в этом опросе

 
 
Рейтинг 4.68/543: Рейтинг темы: голосов - 543, средняя оценка - 4.68
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
#1

Написание статей

28.05.2009, 11:56. Просмотров 98203. Ответов 27
Метки нет (Все метки)

Уникальные идентификаторы в Access

В чём проблема
MS Access не предоставляет нам возможности выбора способа уникальной идентификации строк таблиц. Единственный вариант - счётчик. Правда, надо отдать ему должное - в подавляющем большинстве случаев этого достаточно.

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

Другой неприятной особенностью счётчика явлается то, что иногда значения всё же дублируются, особенно при отсутствии уникального индекса для такого поля.
Способы решения

Традиционный метод генерации уникального значения основывается на создании специальной таблицы с полем, которое изменяется по заданному алгоритму при каждом новом обращении к нему клиентских приложений. С полученным таким образом значением можно провести ещё какие-нибудь манипуляции и записать в ключевое поле. Недостатком способа является его явная трудоёмкость и сомнительная надежность. В частности, функцию, используемую для получения такого уникального идентификатора, нельзя использовать в свойстве "Значение по умолчанию" поля таблицы.

Другим методом является выделение диапазонов счётчика для каждой из баз. Такой способ очень даже не плох. Недостатком можно считать необходимость заранее планировать количество и размер диапазонов. Иначе, кому-то может просто не хватить номеров. Кроме того, установка начальных значений счётчиков всё же требует дополнительных действий.

Третий подход подразумевает создание выражения, результатом которого было бы значение, подходящее для использования в качестве уникального идентификатора. Также требуется возможность указать это выражение в свойстве "Значение по умолчанию" поля таблицы. Ниже подробно описаны два таких выражения: одно строкового, а другое числового типа.
Идентификатор типа String

Получение уникального значения в данном случае основано на генерации строки из 16-ти символов. Первым идёт самый левый из аргументов командной строки. Значение командной строки можно задать не только в параметре запуска /cmd, но и из программы:
Visual Basic
1
Application.SetOption "Command-Line Arguments", "W"
За ним следуют шестнадцатеричные значения текущей даты и времени. Оставшиеся 7 символов занимает случайное число (также в шестнадцатеричном формате). В итоге получается следующее:

Visual Basic
1
ID = Left(Command(), 1) & Hex(Now() Mod 2 ^ 16) & Hex((Now() - Int(Now())) * 65535) & Hex(Rnd() * (2 ^ 28-1))
Здесь:
Visual Basic
1
Left(Command(), 1)
- любой подходящий символ (должен быть первым в аргументе командной строки)
Visual Basic
1
Hex(Now() Mod 2 ^ 16)
- дата по модулю 65536 (чтобы было не более 4 символов)
Visual Basic
1
Hex((Now() - Int(Now())) * 65535)
- время масштабированное до 65535 (чтобы было не более 4 символов)
Visual Basic
1
Hex(Rnd() * (2 ^ 28-1))
- случайное число в диапазоне от 0 до 2^28-1 (чтобы было не более 7 символов)

При таком способе, количество клиентов в системе ограничено числом допустимых символов для первого (левого) байта в строке. Определённо, таковых найдётся не менее сотни. Если нужно больше, то можно увеличить количество начальных символов. Размер идентификатора при этом, разумеется, тоже возрастёт. Дополнительным плюсом является то, что такой идентификатор можно без всяких переделок использовать в качестве ключа для TreeView.
Идентификатор типа Currency

Этот способ создания уникального идентификатора является развитием предыдущего. Он позволяет вдвое уменьшить размер поля и ускорить все операции с ним, так как работа с числами происходит быстрее, чем со строками. Функция получается, правда, более громоздкая:

Visual Basic
1
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 можно следующей командой:

Visual Basic
1
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-й) Случайное число
Знак числа (большая или меньшая половина номеров)
Visual Basic
1
IIf(Val(Command()) > 63, 1, -1)
Номер из меньшей (1...63) или большей (64...127) половин. Чтобы уместиться в тип Currency, номер не должен превышать 63. Из-за этого использована функция Abs.

Visual Basic
1
CCur(Abs(Val(Command()) - 64) * (2 ^ 57) / 10000)
Дата. Деление по модулю 2 ^ 15 позволяет втиснуться в отведенные 15 бит, сохраняя уникальность при этом около 80 лет.

Visual Basic
1
CCur(CCur((Int(Now()) Mod 2 ^ 15) * (2 ^ 42) / 10000)
Время с точностью до ~1,3 секунды. В промежутке от 00:00:00 до 23:59:59 принимает значение от 0 до 0,99999 и масштабируется до нужных 16 бит умножением на 65535.

Visual Basic
1
CCur(((Now() - Int(Now())) * 65535) * (2 ^ 26) / 10000)
Случайное число в диапазоне от 0 до 2 ^ 26 - 1. Уменьшение диапазона приводит к возникновению повторов.

Visual Basic
1
CCur(Rnd() * (2 ^ 26 - 1)) / 10000))
Заключение

Второй способ, очевидно, является более предпочтительным, так как позволяет создавать более компактные идентификаторы. Кроме того, он позволяет относительно безболезненно перейти от использования счётчиков, так как работа со строками гораздо сильнее отличается от работы с типами Long или Currency, чем они отличаются друг от друга.

Однако, есть и недостатки
. Прежде всего, это ограниченное количество клиентов в системе (не более 127), вызванное сложностью втиснуться в рамки 8-ми байтного числа. Также, нет полной гарантии, что случайные числа не повторятся в пределах тех 1,3 секунды, когда уникальность ключа определяется исключительно работой генератора случайных чисел. В случае такого повтора возникнет ошибка дублирования, которая потребует повтора всей операции добавления записей. Правда, надо отдать должное Access'совской функции Rnd(): она достаточно долго генерирует неповторяющийся поток значений.
3
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
28.05.2009, 11:56
Ответы с готовыми решениями:

Сжатие базы данных по варианту 6.4. из темы Написание статей
Выполнил все рекомендации изложенные в пункте 6.4.. На последнем этапе застрял....

Написание формул
Здравствуйте, подскажите пожалуста где можно прочитать как составлять формулы в...

Написание формулы
Как правильно записать формулу подсчета накрутки на товар. есть таблица...

Написание триггеров к БД
Доброго времени суток! Необходима помощь в написании триггеров на SQL к БД...

Написание SQL запросов
привет всем! нужна помощь в написании нескольких запросов. извините, просто...

27
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
09.06.2009, 11:24  [ТС] #2
Лучший ответ Сообщение было отмечено ildwine как решение

Решение

Хранение изображений в БД
В настоящее время есть 5 методов хранения информации в БД.
1) Хранение как объектов OLE
Недостатки - большой обьем, необходимость установки набора соответствующих приложений.
Достоинство - простота использования
Пример: учебная база "Борей"
В начале используют все. Потом в зависимости от поставленных задач. И от количества и объема рисунков.

2) Хранение в двоичном формате DIB в поле объектов OLE
Недостатки - большой обьем, необходимость писать дополнительный код для выполнения загрузки рисунков в БД (но код не слишком сложный, есть типовые наработки).
Достоинство - быстрота вывода рисунков.
Используется редко т.к. по сравнению с первым способом объем базы не уменьшается, а сложности при программировании растут.

3) Хранение в сжатом двоичном формате DIB в поле объектов OLE
Недостатки - необходимо использовать или разрабатывать самому системы архивации данных, дополнительный код.
Достоинство - меньший объем БД по сравнению с двумя первыми способами.
Пример: sd_Foto.zip с использованием библиотеки zlib.dll. или sd_dbFoto3_97.zip
библиотека zlib.dll для Win2000 Pro и WinXP: zlib123dll.zip

4) Хранение файлов в формате JPG и GIF в поле объектов OLE и загрузка их в элемент управления Image (рисунок) через временный файл
Недостатки - необходимо использовать временный файл для рагрузки рисунка, увеличение времени загрузки рисунка, дополнительный код.
Достоинство - меньший объем БД по сравнению с тремя первыми способами.
Пример: pictures.rar или sd_dbFoto4_97.zip

5) Хранение в базе данных путей к рисункам в формате JPG и GIF и загрузка их в элемент управления Image (рисунок)
Недостатки - необходимо следить за целостностью набора рисунков, увеличение времени загрузки рисунка, дополнительный код.
Достоинство - самый маленький объем БД по сравнению с четырьмя первыми способами.
Пример: sd_dbFoto5_97.ZIP
23
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
09.10.2009, 16:19  [ТС] #3
Работа со строками
Откровенно говоря, возможности для работы со строками в MSA небольшие и приходится писать собственные функции. О них и речь...
Поиск последнего символа в строке
Поиск последнего символа в строке, например, последней точки в имени файла для определения расширения или последнего слэша в пути к файлу для определения имени файла в пути.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
'Вызов функции
MsgBox FndSmb(".","main.html")
'Сама функция
Public Function FndSmb(smb As String, stroka As String) As Long
Dim a As Long
Dim b As Long
a = 1
While a > 0
    b = a
    a = InStr(a + 1, stroka, smb)
Wend
FndSmb = b
End Function

Замена символа или последовательности символов
Замена символа или последовательности символов, чем-то похоже на одноименную функцию в РНР. Пришлось написать, когда возникла необходимость в использовании формул, задаваемых пользователем. Проблема была в том, что внутри кода разделитель мантиссы запятая, а вот для фукнции Eval нужна точка. В итоге получилась гораздо более функциональная вещь.
P.S. Начиная с версии 2000 в MSA есть функция replace(). Так что можете пользоваться ею.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'Вызов функции
MsgBox str_replace(",",".","9,9*10,17")
'Сама функция
Public Function str_replace(s1 As String, s2 As String, s As String) As String
Dim n1 As Long
Dim n2 As Long
Dim v1 As String
Dim v2 As String
Dim v3 As String
 
v3 = s
n2 = 1
n1 = InStr(n2, s, s1)
 
If n1 > 0 Then
    Do
        v1 = Mid(v3, 1, n1 - 1)
        v2 = Mid(v3, n1 + Len(s1), Len(v3) - n1)
        v3 = v1 & s2 & v2
        n2 = n1 + Len(s2)
        n1 = InStr(n2, v3, s1)
    Loop Until n1 < 1
End If
 
str_replace = v3
End Function

функция для получения элемента из строки с разделителями
Более сложная функция для получения элемента из строки с разделителями. Возникла из задачи, когда в одном поле таблицы оказались данные, которые необходимо было разнести по разным столбцам.
Опять же в РНР такая функция есть (split), а вот в MSA нет.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
'Вызов функции
MsgBox ExpandStr("Waw;2347859;dfskgdkf",";",2) '2347859
'Сама функция
Public Function ExpandStr(stroka As String, Razdel As String, numpos As Long)
Dim n1 As Long
Dim s1 As String
Dim v1 As String
Dim v2 As String
Dim v3 As String
Dim i As Long
 
v3 = stroka
s1 = Razdel
n1 = InStr(1, v3, s1)
i = 0
 
If n1 > 0 Then
    Do
        v1 = Mid(v3, 1, n1 - 1) 'возвращает слово до поисковой строки
        v2 = Mid(v3, n1 + Len(s1), Len(v3) - n1) 'возвращает слово после поисковой строки
        v3 = v2 'склейка
        n1 = InStr(1, v3, s1) 'выполняем новый поиск подстроки
        i = i + 1
    Loop Until n1 < 1 Or i >= numpos 'если такой подстроки нет, то обрываем поиск
End If
If n1 < 1 And i < numpos Then
    ExpandStr = v2
Else
    ExpandStr = v1
End If
End Function
6
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
09.10.2009, 17:06  [ТС] #4
3 вида меню в MS Access
То, что первым видит пользователь в программе – это меню. От него зависит (и не только) на сколько удобно будет работать с программой. С течением времени определенные подходы, которые я видел, классифицировались в следующие виды меню:
- формы с кнопками,
- кнопочная форма (на основе мастера),
- строка меню.

Я заметил, что «новички» начинают с форм с кнопками, затем открывают для себя кнопочные формы, а если встает задача сделать, как классическом текстовом редакторе, то переходят к строке меню или используют вместо нее панель инструментов. Конечно, бывают исключения и это только мои наблюдения.

Очень долгое время я думал, что самое лучшее и удобное меню – это строка меню. Но как показала жизнь, для каждого класса задач подходит свое меню.

1 Формы с кнопками
При этом подходе создается множество однотипных форм с кнопками или группой переключателей. Этот метод очень активно использовался в старых ДОСовских программах.

Это очень удобно использовать, когда пользователю при работе с одной из функций не нужна другая функция, которая вызывается из меню. Примером таких программ могут служить любые, в которых происходит потоковая регистрация и пользователю некогда переключаться между клавиатурой и мышкой.

К минусам такого способа можно отнести большое количество форм и муторность в изменении этого меню. Для пользователя может быть не удобно закрывать или сворачивать текущие формы, чтобы увидеть меню и открыть необходимую форму.

Очень не рекомендую использовать группы переключателей в качестве кнопок, переходить клавишами по такому меню не удастся.


2 Кнопочная форма (на основе мастера)
В этом варианте существует только одна форма и мастер редактирования пунктов. Из недостатков – при открытии любая формы, форма меню будет не видна.

При ближайшем рассмотрении оказалось, что это обыкновенная форма с х кнопками и надписями и с системной таблицей в качестве источника данных.

Не знаю почему, но мне этот вариант мне не нравится. Я лучше сам его реализую при необходимости.


3 Строка меню
Это мой самый любимый способ, т.к. очень просто изменять и все время на виду. Да и очень редко мне доводится разрабатывать программы для людей, не пользующихся мышкой.



Чтобы меню выглядело при запуске программы как на картинке, придется немножко пошаманить.

При создании меню (Сервис->Настройка), по умолчанию создается панель инструментов. По этому, выбрав созданное меню, необходимо нажать кнопку свойства. Необходимо настроить его следующим образом:


Я изменил тип на «Строка меню» и убрал галочку «Отображение и скрытие», чтобы пользователь ее не мог скрыть. Снимать все галочки не рекомендую, если будет желание то после этого обязательно проверьте, что из этого получилось и подойдет ли пользователю. А то можете получить проблему из-за меню. Также можно убрать перемещение, но только после того, как закончите сами ее настраивать.

Теперь необходимо зайти в Параметры запуска (Сервис –> Параметры запуска).


Тут я выбираю свою строку меню и убираю отображение окна базы данных. В таком режиме я и работаю.

Как вы заметили можно и свое контекстное меню сделать. Или убрать панели инструментов по умолчанию. Не рекомендую этим увлекаться. Например, панель инструментов отчетов ой как нужна, чтобы напечатать. А на панели инструментов для форм есть такая полезная штуковина как сортировка.

После того, как вы перезапустите свою БД, то всегда будет отображаться ваше меню. А стандартного не будет. Чтобы его отобразить/скрыть достаточно нажать Ctrl+F11. Очень удобно
.
Название: image001.png
Просмотров: 10784

Размер: 4.6 Кб
Написание статей
Написание статей
d=1255093425[/IMG]

Я изменил тип на «Строка меню» и убрал галочку «Отображение и скрытие», чтобы пользователь ее не мог скрыть. Снимать все галочки не рекомендую, если будет желание то после этого обязательно проверьте, что из этого получилось и подойдет ли пользователю. А то можете получить проблему из-за меню. Также можно убрать перемещение, но только после того, как закончите сами ее настраивать.

Теперь необходимо зайти в Параметры запуска (Сервис –
9
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
13.10.2009, 10:42  [ТС] #5
О сжатии БД
Q1. Из-за чего растет размер файла БД?
1.1. При удалении данных в таблицах БД записи из файла БД не удаляются, а просто помечается как удаленные (удаляются логически). Т.е. стертые данные так и лежат в базе, в результате файл по мере работы постепенно растет;

1.2. При внесении изменений в формы, отчеты, запросы и т.п. прежние копии редактируемых объектов, по аналогии с записями в таблицах (см. выше), удаляются логически, но не физически, что так же приводит к "распуханию" файла БД;

1.3. Access во время выполнения Проекта активно пользуется Скрытыми таблицами Проекта (БД), поэтому рост размеров файла БД может наблюдаться даже в MDE/ADE-файлах (редактировать формы, отчеты и т.п. в которых невозможно), не содержащих таблицы с данными пользователя;

1.4. Распухание БД возможно, если при выполнении каких-либо задач создаются временные таблицы (например, при формировании сложных отчетов), а затем данные временные таблицы уничтожаются. Уничтожаются они так же логически (просто помечаются как удаленные).


Q2. За счет чего размер файла БД уменьшается при сжатии?
При сжатии из файла БД физически удаляются записи и объекты БД, помеченные как "удаленные" (логически удаленные).


Q3. Зачем необходимо сжимать БД?
3.1. Для повышения производительности Проекта (быстродействия БД). Во время сжатия Access не только физически удаляет логически удаленные записи, что само по себе увеличивает производительность (отпадает необходимость фильтровать действительные данные от логически удаленных данных), но и дефрагментирует таблицы, в результате чего увеличивается скорость доступа к данным;

3.2. Для повышения надежности БД. На основе эмпирических данных замечено, что регулярное сжатие (и соответственно, восстановление) БД повышает "иммунитет" Проекта к глюкам;

3.3. В некоторых случаях сжатие/восстановление БД просто необходимо. Если БД "упала", то первым делом необходимо сделать ее (уже упавшей) резервную копию и вторым шагом произвести сжатие/восстановление;

3.4. В качестве профилактических мер после неких форс-мажорных обстоятельств. Например, если во время работы БД был выключен свет, либо пользователь сам выключил компьютер, не закрыв БД, либо произошло "падение" сети в момент работы БД и т.п.

3.5. Заново создается статистика по таблицам (количество записей в таблицах, наличие и типы связей, присутствие индексов и т.п.), которая в дальнейшем будет использована Оптимизатором выполнения запросов. Кроме того, сбрасывается флаг компиляции запросов, что приводит при первом следующем выполнении запроса к новому построению плана выполнения запроса, но уже с учетом обновленной статистики, что увеличивает скорость выполнения запросов. Этот пункт можно считать единственным минусом сжатия/восстановления БД, так как на построение плана запроса требуется некоторое время (небольшое).


Q4. Как часто необходимо сжимать БД?
Теоретически, сжимать БД необходимо при каждом закрытии БД. Практически это не всегда целесообразно, т.к. занимает определенное время и в некоторых случаях отрицательно сказывается на производительности БД в момент первого выполнения запросов (см. Пункт 3.5).
Оптимальным вариантом является некий график сжатия БД: раз в день, раз в два дня, раз в неделю и т.п., который определяется исходя из: 1) Количества одновременно работающих с БД пользователей, 2) размеров БД, 3) из частоты обновления данных в БД (удаление, добавление, редактирование записей) и т.п.


Q5. Как сжимать БД?
5.1. Через меню: Сервис/Служебные программы/Сжать и восстановить базу данных;

5.2. Через меню: Сервис/Параметры/Вкладка "ОБЩИЕ"/Флаг "Сжимать при закрытии". С помощью данной настройки можно организовать автоматическое сжатие БД при каждом ее закрытии. Действие данного флажка относится только к открытой базе данных, при этом подключенные (прилинкованные) базы данных сжаты не будут. Как сжать прилинкованную БД см. Вопрос/Ответ Q6;

5.3. Через преобразование БД к предыдущей версии БД (Сервис/Служебные программы/Преобразовать базу данных…) с последующим преобразованием полученного файла к текущей версии БД. Данный способ наиболее эффективен для сжатия БД после внесения изменений в его интерфейсную часть (редактирование форм, отчетов, кода и т.п.), так как иногда удается обнаружить ряд скрытых ошибок, зачастую возникших из-за сбоев самого Access, а так же физически удалить из файла БД логически удаленные объекты.

5.4. Через импорт в пустой (новый) файл БД. По преследуемым целям схож с предыдущим пунктом.

5.5. Через выполнение запуска Access в командной строке со специальными параметрами. Например:
"C:\Program Files\Microsoft Office\Office\Msaccess.exe" "С:\Мои документы\MyDB.mdb" /Excl /Compact
5.6. Через VBA-код, при этом можно использовать несколько различных технологий программного сжатия БД (См. ответы на вопросы Q6 и Q7).

5.7. C помощью утилиты JetComp.exe, которая помимо сжатия умеет также восстанавливать некоторые повреждения .mdb-файлов, которые невозможно исправить средствами MS Access. Справку по параметрам командной строки jetcomp.exe можно получить с помощью
jetcomp.exe /?


Q6. Как сжать БД из VBA-кода моего Проекта?
6.1 - Вариант 1

Можно программно нажать кнопку "Сжать и восстановить базу данных" (меню Сервис/Служебные программы). Этот вариант является наиболее простым, но в то же время наименее гибким из предложенных далее, а также обладает рядом серьезных недостатков (см. ниже):

Visual Basic
1
2
3
4
5
6
7
8
9
Public Function AutoCompact() 
  With CommandBars.Add(, 1, , True) 
    .Controls.Add 1, 2071, , , True 
    .Visible = True 
    .Controls(1).SetFocus 
    DoEvents 
    SendKeys "~" 
  End With 
End Function
Достоинства:
# Функция позволяет сжать текущую БД (базу данных, в которой выполняется VBA-код, вызывающий сжатие). Данный вариант является единственным вариантом, позволяющим сжимать текущую не закрытую БД. Не смотря на это, авторы FAQ настоятельно рекомендуют ознакомиться с пунктом 6.4, где рассмотрен более гибкий и надежный вариант реализации сжатия текущей БД;
# Пример сообщает о наличии подобного варианта "программного сжатия БД" и раскрывает его недостатки.

Недостатки:
# Сжатие происходит только текущей БД (базы, в котором выполняется код), таким образом, если БД разделена на Интерфейсную часть и часть с Данными (см. Вопрос/Ответ Q8.3), то будет сжата только Интерфейсная часть в которой выполняется код, а часть с Данными останется несжатой;
# БД после сжатия перезапускается (открывается повторно);
# После последней строки в функции не должно быть никакого дополнительного кода, т.к. это может привести либо к невозможности выполнить сжатие, либо к невозможности выполнить данный дополнительный код;
# Метод не дает программного контроля над выполняемым сжатием, т.е. невозможно отследить (перехватить) и обработать соответствующим способом ошибки, которые могут возникнуть в процессе сжатия БД.

6.2. Вариант 2
Сжатие через DAO-метод DBEngine.CompactDatabase.

Данный метод сжатия наиболее предпочтителен для MDB/MDE форматов БД расположенных "настольно" (без сети) или для сетевых БД, организованных по технологии "Файл-Сервер". Основным условием является доступность (подключение) Библиотеки DAO.
Метод не пригоден для сжатия текущей БД (базы данных, в которой выполняется процедура сжатия), но прекрасно подходит для разделенных БД (см. Пункт 8.3). Для сжатия базы данных, в которой выполняется программный код, инициирующий данное сжатие, можно воспользоваться Вариантом 1 (см пункт 6.1) или, что намного лучше, Отдельным процессом, который и произведет данное сжатие (см. пункт 6.4). Кроме того можно попытаться воспользоваться (на свой страх и риск) вариантом, приведенным в Пункте 7.2

Сжатие производится следующим образом:

- если к БД подключаются несколько пользователей, то перед сжатием БД необходимо убедиться, что ни один пользователь не подключен к базе. В противном случае система сгенерирует перехватываемую ошибку и сжатие БД выполнено не будет;

- сформировать полный путь к сжимаемой БД и полный путь к новому (временному) файлу, в который сжатая БД будет записана;

- сжать БД;

- скопировать новый (появившийся в результате сжатия БД) файл на место старого (копирование под именем, которое принадлежало старому файлу);

- удалить новый (временный) файл.

В качестве примера можно привести два варианта реализации сжатия БД DAO-методом, отличающихся способами манипулирования файлами:

6.2.1. Пример 1
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
'ФУНКЦИЯ СЖАТИЯ БД DAO-Методом'
'  gflngCompactDatabase(...)'
'ВХОДНЫЕ ПАРАМЕТРЫ ФУНКЦИИ:'
'  CompactingDBPathAndName - строковый параметр, задающий ПОЛНЫЙ ПУТЬ (путь + имя файла)'
'     к сжимаемой БД.'
'  BackupBeforeCompactDB - необязательный логический параметр, указывающий на'
'     необходимость сделать перед сжатием резервную копию сжимаемой БД (резервная'
'     копия выкладывается в файл с именем "ИмяСжимаемогоФайла_Backup"). При'
'     отсутствии параметра резервное копирование не производится.'
 
'ВОЗВРАЩАЕМОЕ ФУНКЦИЕЙ ЗНАЧЕНИЕ:'
'  = 0, если сжатие произведено;'
'  = Номеру возникшей ошибки, если выполнить сжатие не удалось.'
 
'ОСОБЕННОСТИ:'
'  Для выполнения процедуры сжатия автоматически создается временный файл'
'     с именем "ПолныйПуть\ИмяСжимаемогоФайла_Temp".'
'  Резервное копирование, выполнение которого определяется параметром "BackupBeforeCompactDB",'
'     производится в файл с именем "ПолныйПуть\ИмяСжимаемогоФайла_Backup"), при'
'     этом старая копия резерва перезаписывается новой (фактически удаляется).'
'  В случае, если сжимаемая БД открыта, то файл БД не будет скопирован (соответствующая'
'     ошибка появится в момент копирования БД).'
 
Public Function gflngCompactDatabase( _
CompactingDBPathAndName As String, _
Optional BackupBeforeCompactDB As Boolean = False) As Long
Dim strTempFile As String
On Error GoTo ErrHandler
'Формируем имя для временного ("принимающего") файла'
  strTempFile = Left(CompactingDBPathAndName, (Len(CompactingDBPathAndName) - 4)) & _
  "_Temp" & Right(CompactingDBPathAndName, 4)
'Создаем (если надо) резервную копию файла БД перед сжатием'
  If BackupBeforeCompactDB = True _
  Then FileCopy CompactingDBPathAndName, _
  Left(CompactingDBPathAndName, (Len(CompactingDBPathAndName) - 4)) & _
  "_Backup" & Right(CompactingDBPathAndName, 4)
'Сжимаем файл БД (с перезаписью сжатого файла в новый файл)'
  DBEngine.CompactDatabase CompactingDBPathAndName, strTempFile, dbLangCyrillic
'Перезаписываем сжатый (временный файл) на место несжатого (старого файла)'
  FileCopy strTempFile, CompactingDBPathAndName
'Удаляем временный файл'
  Kill strTempFile
Exit Function
ErrHandler:
'обрабатываем возможные ошибки'
  gflngCompactDatabase = Err.Number
  Err.Clear: Exit Function
End Function
Достоинства:
# Для манипулирования файлами (получения имени для временного файла и копирование файла) функция использует стандартные команды Access и не требует наличия на компьютере библиотеки "Microsoft Scripting Runtime" (SCRRUN.DLL), которая (как показывает практика) может отсутствовать;

Недостатки:
# Для получения имени временного файла функция добавляет к имени сжимаемого файла суффикс "_Temp" ("ПолныйПуть\ИмяСжимаемойБД_Temp"), поэтому в случае, если имеется рабочая БД с подобным именем, то по окончании процесса сжатия она будет удалена. Данный недостаток удается избежать либо приняв правило "Не присваивать рабочим файлам БД имени, оканчивающегося на '_Temp'", либо изменив функцию (заменить добавление суффикса "_Temp" на путь и имя файла, специально отведенного для сжатия БД), либо воспользовавшись технологией, приведенной в следующем Примере:

6.2.2. Пример 2
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
'ФУНКЦИЯ СЖАТИЯ БД DAO-Методом с использованием FileSystemObject для манипулирования файлами '
'  gflngCompactDatabaseFSO(...)'
'ВХОДНЫЕ ПАРАМЕТРЫ ФУНКЦИИ:'
'  CompactingDBPathAndName - строковый параметр, задающий ПОЛНЫЙ ПУТЬ (путь + имя файла)'
'     к сжимаемой БД.'
'  BackupBeforeCompactDB - необязательный логический параметр, указывающий на'
'     необходимость сделать перед сжатием резервную копию сжимаемой БД (резервная'
'     копия выкладывается в файл с именем "ИмяСжимаемогоФайла_Backup"). При'
'     отсутствии параметра резервное копирование не производится.'
 
'ВОЗВРАЩАЕМОЕ ФУНКЦИЕЙ ЗНАЧЕНИЕ:'
'  = 0, если сжатие произведено;'
'  = Номеру возникшей ошибки, если выполнить сжатие не удалось.'
 
'ОСОБЕННОСТИ:'
'  Резервное копирование, выполнение которого определяется параметром "BackupBeforeCompactDB",'
'     производится в файл с именем "ПолныйПуть\ИмяСжимаемогоФайла_Backup"), при'
'     этом старая копия резерва перезаписывается новой (фактически удаляется).'
'  В случае, если сжимаемая БД открыта, то файл БД будет скопирован и соответствующая'
'     ошибка появится только в момент сжатия БД.'
 
Public Function gflngCompactDatabaseFSO( _
CompactingDBPathAndName As String, _
Optional BackupBeforeCompactDB As Boolean = False) As Long
On Error GoTo ErrHandler
Dim strTempFile As String
Dim objFileSystem As Object
'Создаем объект Файловой системы '
 
  Set objFileSystem = CreateObject("Scripting.FileSystemObject")
'Создаем (если надо) резервную копию файла БД перед сжатием'
 
  If BackupBeforeCompactDB = True _
  Then objFileSystem.CopyFile CompactingDBPathAndName, _
  Left(CompactingDBPathAndName, (Len(CompactingDBPathAndName) - 4)) & _
  "_Backup" & Right(CompactingDBPathAndName, 4)
'Получаем имя для временного ("принимающего") файла'
 
  strTempFile = objFileSystem.GetTempName
'Сжимаем файл БД (с перезаписью сжатого файла в новый файл)'
 
  DBEngine.CompactDatabase CompactingDBPathAndName, strTempFile, dbLangCyrillic
'Перезаписываем сжатый (временный файл) на место несжатого (старого файла)'
 
  objFileSystem.CopyFile strTempFile, CompactingDBPathAndName, True
'Удаляем временный файл'
  Kill strTempFile
'Уничтожаем объект Файловой системы'
  Set objFileSystem = Nothing
Exit Function
ErrHandler:
'обрабатываем возможные ошибки'
 
  gflngCompactDatabaseFSO = Err.Number
  Err.Clear: Exit Function
End Function
Достоинства:
# Для получения имени временного файла функция использует специальный метод объекта FileSystemObject, генерирующий уникальное имя для файла, что исключает возможность перезаписать (фактически удалить) какой-либо существующий файл.

Недостатки:
# Для манипулирования файлами (получения имени для временного файла и копирование файла) функция использует библиотеку "Microsoft Scripting Runtime" (SCRRUN.DLL), которая (как показывает практика) может отсутствовать на компьютере. Данный недостаток удается избежать воспользовавшись предыдущим примером DAO-реализации сжатия БД (пункт 6.2.1).

6.3. Вариант 3
Сжатие через JRO-метод ("расширение" ADO) JRO.JetEngine.

Данный метод сжатия наиболее предпочтителен для ADP/ADE форматов БД, обычно не использующих DAO-библиотеку.

Сжатие производится следующим образом:

- Отключаем от базы данных клиента, с которого запускается процедура сжатия. На данном этапе отладки необходимо убедиться, что все соединения, рекордсеты и т.п. закрыты, т.е. ldb-файл базы данных отсутствует.

- Проверяем, подключен ли кто-нибудь еще к базе данных, что можно сделать двумя вариантами:

1) Проверить наличие .ldb файла

Visual Basic
1
If DIR(полный путь к ldb файлу)<>"" then ...
2) Использовать метод ADO OpenSchema для получения информации о подключенных пользователях (если есть файл рабочей группы) или машинах (в данном примере именно так, где имя машины - 10 символов). Вариант более гибкий, т.к. можно узнать, кто именно блокирует файл (в данном примере проверяем подключен кто-то или нет, но из полученного рекордсета легко можно забрать и реальные имена пользователей/машин).

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Dim cnn As ADODB.Connection, rst As ADODB.Recordset
Dim je As New JRO.JetEngine 
Dim lngConnected As Long, strCurPCName As String, strBE As String, strBETemp As String
Const adhcUsers = "{947bb102-5d43-11d1-bdbf-00c04fb92675}"
strBE = "Полный путь к файлу БД"
strBETemp = "Полный путь к новому (сжатому) файлу БД"
  Set cnn = New ADODB.Connection
  cnn.Provider = "Microsoft.Jet.OLEDB.4.0"
  cnn.Open "Data Source=" & strBE
  'Используем элемент Connection Control (Jet версии не младше 4.0) для'
  'запрета подключения новых пользователей.'
  cnn.Properties("Jet OLEDB:Connection Control") = 1
  Set rst = cnn.OpenSchema(Schema:=adSchemaProviderSpecific, SchemaID:=adhcUsers)
' strCurPCName - имя машины, с которой запускается процедура'
 
  strCurPCName = Environ("COMPUTERNAME")
      With rst
          Do Until .EOF
          ' Считаем кол-во подключенных машин, исключая машину, с которой
          ' запущена процедура. Наверняка вычленить реальное имя машины из
          ' этого поля можно более красивым и правильным способом, мне просто
          ' лень было, у меня и так работает:-)'
              If Not strCurPCName = Left(.Fields(0), 10) Then lngConnected = lngConnected + 1
              .MoveNext
          Loop
      End With
      If lngConnected > 0 Then
         ' База данных заблокирована другим пользователем->сжать не удастся
         ' -> выходим любым приемлемым способом, не забыв закрыть rst и cnn'
 
      End If
      ' База не заблокирована -> переходим к сжатию. Вариант с принудительным
      ' отключением пользователей здесь не рассматривается, т.к. лично я
      ' считаю его приемлемым только в аварийных случаях.'
 
  'Закрываем открытый ранее рекордсет'
 
  If Not rst Is Nothing Then rst.Close
  Set rst=nothing
- Производим сжатие, при этом должна быть подключена библиотека Microsoft Jet and Replication Objects x.x Library (JRO)

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
    ' Проверяем наличие временного файла (возможно остался
    ' от предыдущей неудачной попытки сжатия) и удаляем его
 
    If Dir(strBETemp) <> "" Then Kill strBETemp
    ' Закрываем объект cnn, открытый в п.2, иначе сжать данные не получится'
 
    Set cnn=Nothing
    ' Сжимаем'
 
    je.CompactDatabase "Data Source=" & strBE & ";", _
        "Data Source=" & strBETemp & ";"
    ' Маловероятно, но гипотетически за время сжатия, 
    ' кто-нибудь мог подключиться к файлу БД, поэтому можно еще раз
    ' проверить наличие подключенных пользователей (см. пример выше),
    ' если никто не подключен, то удаляем старый файл и
    ' переименовываем новый сжатый файл. Если кто-то все-таки
    ' успел открыть БД, то просто выходим, оставляя временный
    ' сжатый файл. Добавить обработку такой ситуации по вкусу.
 
    Kill strBE
    Name strBETemp As strBE
    Set je = Nothing
6.4. Вариант 4

Вынесение в отдельный процесс кода, сжимающего БД, что позволяет сжать любые базы данных (в том числе и ту, которая инициировала процесс сжатия БД). Данный вариант является наиболее предпочтительным и гибким решением, позволяющим комбинировать рассмотренные ранее варианты программного сжатия БД, а также производить дополнительное обслуживание баз данных.

Как это работает:

База данных, в которой выполняется код (Клиентская часть или Неразделенная БД), перед закрытием (возможно, не при каждом закрытии: См. Вопрос/Ответ Q4) вызывает другую программу, которая производит все необходимые действия по обслуживанию БД.
В приведенном ниже примере в качестве обслуживающих действий выполняется сжатие Вызвавшей БД и Дополнительной БД, при этом в качестве Сервис-Провайдера используется Access.

Для реализации описанного механизма:

- Создайте новую базу данных с именем "DBServiceProvaider.mdb", в которой создайте форму. Скопируйте в модуль формы следующий код:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
Const TimeDelay As Long = 250     'задержка в миллисекундах между неудачными попытками сжатия'
 
Const MaxIterations As Long = 10  'количество повторов сжатия при неудачных попытках сжатия'
Dim mlngStep As Long              'номер текущего выполняемого шага'
 
Private Sub Form_Load()
  Me.TimerInterval = 1            'запускаем таймер'
End Sub
 
Private Sub Form_Timer()
  Me.TimerInterval = 0  'останавливаем таймер (исключаем повторное событие в момент сжатия)'
  Select Case mlngStep
  Case 0    'Первый шаг "Обслуживания БД"'
    Call gsTryToCompactDB("C:\Тест\MyDB1.mdb")
  Case 1    'Второй шаг "Обслуживания БД"'
    Call gsTryToCompactDB("C:\Тест\MyDB2.mdb")
  'Case N    ''N-ный шаг "Обслуживания БД"'
    'Действия по обслуживанию БД...'
    'Приращиваем значение mlngStep для выполнения следующего шага обслуживания'
    'Запускаем таймер для выполнения следующего шага'
  Case 2    'заключительный шаг (N+1), заканчивающий выполнение Проекта "Обслуживания БД"'
    MsgBox "Обслуживание завершено!", vbInformation
    DoCmd.Quit
  End Select
End Sub
 
Private Function gsTryToCompactDB(CompactingDB As String)
Dim lngUserAnswer As Long
Static lngIterationCnt As Long
  If gflngCompactDatabase(CompactingDB) = 0 Then 'сжимаем БД и проверяем, получилось ли'
  'если сжатие произошло...'
    mlngStep = mlngStep + 1
    lngIterationCnt = 0
    Me.TimerInterval = 1
  Else
  'если сжатие не произошло (возникла ошибка)...'
    If lngIterationCnt <= MaxIterations Then
      lngIterationCnt = lngIterationCnt + 1
      Me.TimerInterval = TimeDelay
    Else
      lngIterationCnt = 0
      lngUserAnswer = MsgBox( _
      "В данный момент не получается сжать файл '" & _
      CompactingDB & "'." & vbNewLine & _
      "Попытаться сжать данный файл еще раз?", _
      vbExclamation + vbYesNoCancel, "Не удается сжать БД")
      Select Case lngUserAnswer
      Case vbYes
        Me.TimerInterval = TimeDelay
      Case vbNo
        mlngStep = mlngStep + 1
        Me.TimerInterval = 1
      Case vbCancel
        DoCmd.Quit 'Выход из Acces'
      End Select
    End If
  End If
End Function
Обратите внимание, что в процедуре Private Sub Form_Timer() указан путь к двум сжимаемым БД, который необходимо настроить в соответствии с именами и размещением сжимаемых БД на машине.

- сохраните форму и укажите ее имя в качестве автоматически открываемой формы (Меню Сервис\Параметры запуска\Вывод формы или страницы);

- создайте модуль и разместите в нем функцию, приведенную в Пункте 6.2.1 (можно воспользоваться и Примером из пункта 6.2.2, соответствующим образом откорректировав процедуру gsTryToCompactDB());

- подключите DAO-библиотеку (в случае, если еще не подключена), откомпилируйте код и закройте созданную "DBServiceProvaider.mdb";

- откройте базу, из которой будет вызываться созданный нами "Провайдер Обслуживания БД", и добавьте в соответствующее место (например, на кнопку "Выход", или на событие выгрузки главной формы проекта) код:
Visual Basic
1
2
3
  Shell "C:\Program Files\Microsoft Office\Office\Msaccess.exe " & _
    """C:\Тест\DBServiceProvaider.mdb""", vbMaximizedFocus
  DoCmd.Quit
Обратите внимание, что сначала указывается полный путь к исполнимому файлу Access, а затем полный путь к созданной "DBServiceProvaider.mdb", при этом как тот, так и другой необходимо указать в соответствии с расположением файлов на машине.

Следует отметить, что процедура Private Sub Form_Timer() может содержать сколько угодно шагов, направленных на обслуживание БД.

Код приведен в качестве упрощенного примера и призван показать в общих чертах пути реализации приведенной концепции.


Q7. Что еще можно сделать и почему так делать не надо?
7.1. Можно Программно нажать кнопку "Сжать и восстановить базу данных". Один из наиболее работоспособных вариантов подобного способа сжатия описан в Пункте 6.1. Здесь рассмотрен вариант выполнения аналогичных действий всего лишь одной командой (только для Access 200x):
Visual Basic
1
2
3
4
5
6
7
8
9
10
11
'Для Англоязычной версии Access'
 
CommandBars("Menu Bar").Controls("Tools"). _ 
Controls("Database utilities").Controls("Compact and repair database..."). _ 
accDoDefaultAction
 
'Для Русскоязычной версии Access'
 
CommandBars("Menu Bar").Controls("С&ервис"). _ 
Controls("&Служебные программы").Controls("С&жать и восстановить базу данных"). _ 
accDoDefaultAction
Из приведенного примера видно, что код должен соответствовать локализованной версии Access, именно поэтому использовать данный способ не рекомендуется.

Здесь же можно привести несколько видоизмененную версию описываемого способа сжатия БД:
Visual Basic
1
2
3
4
'Обращение к панели инструментов через индексы'
CommandBars(40).Controls(12). _ 
Controls(7).Controls(2). _ 
accDoDefaultAction
Данный вариант не зависит от локализации Access и работает в версиях 2000 и XP, но гарантировать невозможно, что в следующих версиях индексы останутся прежними, а значит, что приложение использующее данный код в следующих версиях останется работоспособным.

Кроме рассмотренных особенностей использования данного способа сюда можно отнести и все сказанное в пункте 6.1

7.2. Попытаться сжать Текущую БД (базу данных, в которой выполняется код, инициирующий сжатие) можно на основе метода, описанного в Пункте 6.2.2, при этом следует внести изменения в алгоритм выполнения сжатия:

- скопировать текущую (исполняемую) БД во временный файл;

- сжать временный файл в другой временный файл;

- полученный сжатый временный файл скопировать на место текущего (выполняемого) файла.

Данная методика, так же как и методика, описанная в Пункте 7.1, приведена здесь с целью ознакомления со всеми возможными вариантами сжатия БД и настоятельно не рекомендуется к реальному применению! Причин несколько. Во-первых, не всегда получается подменить (перезаписать) файл открытой БД. Во-вторых, если подмена будет "удачной" (система позволит перезаписать файл открытой БД), то это может обернуться полным разрушением БД. В-третьих, читаем Help: "CompactDatabase Method: Copies and compacts a closed database...", т.е. сжимать можно только закрытую (не используемую) БД.


Q8. Что еще следует иметь в виду по данному вопросу?
8.1. Перед сжатием БД рекомендуется создавать резервную копию сжимаемого файла. В случае если сжатие производится после некой аварийной ситуации (см. Пункты 3.3 и 3.4), то данная рекомендация превращается в жесткое требование;

8.2. Как уже было указано в пункте 6, во время сжатия к БД не должны быть подключены пользователи;

8.3. К вопросу о сжатии БД, повышающем скорость выполнения и "глюкоустойчивость" Проекта, можно добавить рекомендацию разделять БД на несколько частей, ключевыми из которых являются "Интерфейсная часть" (формы, отчеты, запросы, модули и т.п.) и "Часть с Данными" (таблицы). Данная рекомендация основана на многих причинах, выходящих за рамки FAQ;

8.4. Во время сжатия БД Автоматические Счетчики в таблицах, генерирующие Последовательные значения при добавлении записей, так же "сжимаются" - принимают значения равные Максимальному значению счетчика в столбце + 1;

8.5. После сжатия БД рекомендуется выполнять дефрагментацию диска (по мере возможности), что положительно сказывается на производительности Проекта уже на системном уровне (скорость доступа к дефрагментированному файлу выше, нежели скорость доступа к файлу, разбросанному по диску).


Источник
10
prog13
Ефрейтор
176 / 147 / 6
Регистрация: 20.07.2009
Сообщений: 226
10.11.2009, 18:39 #6
Объектная модель FSO
Цитата Сообщение от Михайло_ Посмотреть сообщение
А зачем Вам FSO? Почему бы не воспользоваться командами MS-DOS? Это и будет оптимальный подход:
Полностью поддерживаю Ваш совет. Но не хочется видеть вылетающие консольные черные окна при работе с более-менее виндовым интерфейсом. Тем более читал, что FSO очень мощный инструмент работы с объектами.

Введение в объектную модель FSO
Новая особенность VB6 - объектная файловая система (FSO), которая представляет собой основанный на объектах инструмент для работы с папками и файлами. Это позволяет вам использовать знакомый синтаксис object.method с богатым набором свойств, методов и событий для работы с папками и файлами в дополнение к использованию традиционных методов и команд Visual Basic.

Объектная модель FSO дает вашим прикладным программам возможность создавать, изменять, перемещать и удалять папки. С легкостью можно собрать информацию о системных папках, их наличии и расположении. Вы также можете получать всю остальную информацию о дисках, папках и файлах: их имена, атрибуты, даты создания или изменения и т.д.

Объектная модель FSO позволяет намного проще проводить обработку файлов. При обработке файлов ваша основная цель состоит в том, чтобы сохранить данные в эффективном, легко доступном, экономящем ресурсы формате. Всю остальную работу - собственно размещение данных на носителе - берет на себя FSO. Вы сможете создавать файлы, добавлять, изменять и считывать данные.

FSO, которая содержится в библиотеке типов Scripting type library (scrrun.dll), поддерживает создание текстовых файлов и манипулирование ими через объект TextStream. Однако она не поддерживает создание или манипулирование двоичными файлами. Для управления двоичными файлами по-прежнему приходится использовать старые методы - команду Open с соответствующим флагом.

Объекты файловой системы

FSO имеет следующие объекты:
Drive (Дисковод) Позволяет получить информацию о дисководах, присоединенных к системе: их тип, объем (общий, занятый и свободный), метку, серийный номер и т.д. Обратите внимание, что под словом "дисковод" не обязательно подразумевается жесткий диск. Это может быть FDD, CD-ROM, виртуальный диск и т.д. Также не обязательно, чтобы дисководы были физически присоединены к системе - обеспечивается работа с сетевыми дисками.
Folder (Папка) Позволяет создавать, удалять или перемещать папки. Также через этот объект можно получить сведения об их именах, атрибутах, путях к определенным папкам и так далее.
Files (Файлы) Позволяет создавать, удалять или перемещать файлы. Предоставляет доступ к атрибутам, именам и прочим характеристикам файлов.
FileSystemObject Основной объект группы. Содержит методами, которые позволяют создавать, удалять, получать информацию обо всех объектах файловой системы. Также осуществляет управление дисководами, папками и файлами. Многие из методов, связанных с этим объектом, дублированы в других объектах.
TextStream Дает возможность читать и писать текстовые файлы.

Программирование в объектной модели FSO
Программирование в объектной модели FSO включает три основных задачи:
  • создание объекта FileSystemObject путем использования метода CreateObject или объявления новой переменной типа FileSystemObject;
  • использование соответствующего метода в созданном объекте;
  • вызов свойств объекта.

FSO содержится в библиотеке типов, называемой Scripting, которая размещена в файле scrrun.dll. Эту библиотеку надо прописать в меню References | Microsoft Scripting Runtime (если вы этого еще не сделали). С помощью Object Browser можно просмотреть список объектов, свойств, методов, событий и констант, включенных в FSO.

Создание объекта FileSystemObject

Первый шаг - создание объект FileSystemObject для последующей работы с ним. Это можно сделать двумя способами:
  1. объявить переменную как объект:
    PureBasic
    1
    
    Dim fso As New FileSystemObject
  2. используя метод CreateObject, создать объект класса FileSystemObject:
    PureBasic
    1
    
    Set fso = CreateObject("Scripting.FileSystemObject")

Обратите внимание, что первый метод работает только в Visual Basic, в то время как второй метод работает и в Visual Basic, и в VBScript.

Использование соответствующих методов

Следующий шаг - использование соответствующих методов объекта FileSystemObject. Например, если вы хотите создать новую папку или файл, надо использовать методы CreateFolder или CreateTextFile. Если вы хотите удалить объекты, используйте методы DeleteFile или DeleteFolder объекта FileSystemObject, или метод Delete объектов File или Folder. (FSO, естественно, не поддерживает создание или удаление объектов типа Drive). Используя соответствующие методы, вы можете также копировать и перемещать файлы и папки. Обратите внимание, что некоторые функциональные возможности в модели объекта FileSystemObject избыточны. Например, вы можете скопировать файл двумя путями: используя метод CopyFile объекта FileSystemObject, или используя метод Copy объекта File. Оба подхода дают одинаковые результаты и существуют для того, чтобы обеспечить максимум гибкости при программировании.

Работа с существующими дисководами, файлами и папками

Чтобы получить доступ к существующему дисководу, файлу или папке, используется соответствующий метод Get объекта FileSystemObject: GetDrive; GetFolder; GetFile. Например:
PureBasic
1
2
Dim fso As New FileSystemObject, fil As File
Set fil = fso.GetFile("c:\test.txt")
Обратите внимание, однако, что вы не должны использовать методы Get для только что созданных объектов, так как функции создания объектов сразу возвращают вызывающей программе ссылку на созданный объект. Например, если вы создаете новую папку, используя метод CreateFolder, вам не нужно использовать метод GetFolder, чтобы обратиться к ее свойствам (таким как Name, Path, Size и т.д.), так как функция CreateFolder сразу возвращает ссылку на созданный объект. Чтобы получить доступ к свойствам созданной папки, достаточно воспользоваться соответствующей переменной (в данном случае fldr):
PureBasic
1
2
3
4
5
Private Sub Create_Folder()
  Dim fso As New FileSystemObject, fldr As Folder
  Set fldr = fso.CreateFolder("C:\MyTest")
  MsgBox "Created folder: " & fldr.Name
End Sub
Обращение к свойствам объекта

Получив доступ к объекту с помощью методов Get (или создав его), вы можете обращаться к его свойствам. Например, сначала вы получаете доступ к корневому каталогу диска c: методом GetFolder (так как папка уже существует):
PureBasic
1
Set fldr = fso.GetFolder("c:\")
После этого вы можете проверить его свойство Name:
PureBasic
1
Debug.Print "Folder name is: "; fldr.Name
Если Вы хотите узнать дату и время последнего изменения файла, используйте следующий синтаксис:
PureBasic
1
2
3
4
5
Dim fso As New FileSystemObject, fil As File
'Получаем объект File, чтобы сделать запрос
Set fil = fso.GetFile("C:\detlog.txt")
'Печатаем информацию
Debug.Print "File last modified: "; fil.DateLastModified

Работа с дисководами и папками
Объектная модель FSO может работать с дисководами и папками точно так же, как вы работаете с ними с помощью Windows Explorer в интерактивном режиме, т.е. вы можете копировать и перемещать файлы, получать информацию относительно дисководов и папок, и т.д.

Получение информации о дисководах

Объект Drive позволяет вам получать информацию о различных дисководах, присоединенных к системе или физически или через сеть. Его свойства позволяют Вам получить следующую информацию:
  • полный размера дисковода в байтах (свойство TotalSize);
  • количество доступного свободного места на дисководе в байтах (свойства AvailableSpace или FreeSpace);
  • буквенное обозначение дисковода (свойство DriveLetter);
  • тип дисковода: сменный, фиксированный, сетевой, CD-ROM или виртуальный (свойство DriveType);
  • серийный номер дисковода (свойство SerialNumber);
  • тип файловой системы, используемой на носителе: FAT, FAT32, NTFS и т.д. (свойство FileSystem);
  • готов ли дисковод для использования (свойство IsReady);
  • имя ресурсов общего доступа и метку диска (свойства ShareName и VolumeName);
  • путь к устройству или его корневой папке (свойства Path и RootFolder).

Пример использования объекта Drive (Дисковод)

На пример ниже показывается как использовать объект Drive, чтобы получить полную информацию о дисководе. Не забудьте, что в следующем коде все обращения к фактическому объекту Drive осуществляются с помощью переменной drv, содержащей ссылку на объект, которая получена с помощью метода GetDrive:
PureBasic
1
2
3
4
5
6
7
8
9
10
11
Private Sub Command3_Click()
  Dim fso As New FileSystemObject, drv As Drive, s As String
  Set drv = fso.GetDrive(fso.GetDriveName("c:"))
  s = "Drive " & UCase("c:") & " - "
  s = s & drv.VolumeName & vbCrLf
  s = s & "Total Space: " & FormatNumber(drv.TotalSize/1024, 0)
  s = s & " Kb" & vbCrLf
  s = s & "Free Space: " & FormatNumber(drv.FreeSpace/1024, 0)
  s = s & " Kb" & vbCrLf
  MsgBox s
End Sub

Работа с папками
Этот список показывает общие задачи работы с папками и методы для их выполнения:

Создать папку - FileSystemObject.CreateFolder
Удалить папку - Folder.Delete или FileSystemObject.DeleteFolder
Переместить папку - Folder.Move или FileSystemObject.MoveFolder
Копировать папку - Folder.Copy или FileSystemObject.CopyFolder
Возвратить имя папки - Folder.Name
Выяснить, существует ли папка на дисководе - FileSystemObject.FolderExists
Получить образец существующего объекта Folder - FileSystemObject.GetFolder
Выяснить имя папки, родителя папки - FileSystemObject.GetParentFolderName
Выяснить путь системных папок - FileSystemObject.GetSpecialFolder


Пример ниже показывает использование объектов Folder и FileSystemObject для управления папками и получения информацию о них:
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Private Sub Command10_Click()
  'Получаем образец FileSystemObject
  Dim fso As New FileSystemObject, fldr As Folder, s As String
  ' Объект Get Drive
  Set fldr = fso.GetFolder("c:")
  ' Печатаем родительское имя папки
  Debug.Print "Parent folder name is: " & fldr
  ' Печатаем имя дисковода
  Debug.Print "Contained on drive " & fldr.Drive
  ' Печатаем имя корневой папки
  If fldr.IsRootFolder = True Then
    Debug.Print "This folder is a root folder."
  Else
    Debug.Print "This folder isn't a root folder."
  End If
  ' Создаем новую папку объектом FileSystemObject
  fso.CreateFolder ("c:\Bogus")
  Debug.Print "Created folder C:\Bogus"
  ' Печатаем основное имя папки
  Debug.Print "Basename = " & fso.GetBaseName("c:\bogus")
  ' Удаляем недавно созданную папку
  fso.DeleteFolder ("c:\Bogus")
  Debug.Print "Deleted folder C:\Bogus"
End Sub

Работа с файлами
Вы можете работать с файлами в Visual Basic как используя новые объектно-ориентированные методы типа Copy, Delete, Move и OpenAsTextStream, так и с помощью старых функций - Open, Close, FileCopy, GetAttr и т.д. Обратите внимание, что вы можете перемещать, копировать или удалять файлы независимо от типа файла. Имеются две главных категории манипулирования файлами:
  • создание, добавление или удаления данных или чтение файлов;
  • перемещение, копирование и удаление файлов.
Создание файлов и добавления данных с помощью File System Objects

Есть три способа создать последовательный текстовый файл (иногда упоминаемый как "текстовый поток", text stream). Один путь состоит в том, чтобы использовать метод CreateTextFile. Например, создаем пустой текстовый файл:
PureBasic
1
2
Dim fso As New FileSystemObject, fil As File
Set fil = fso.CreateTextFile("c:\testfile.txt", True)
Обратите внимание, что текущая версия FSO еще не поддерживает создание произвольных (random) или двоичных (binary) файлов.

Другой путь состоит в том, чтобы использовать метод OpenTextFile объекта FileSystemObject с установкой флага ForWriting:
PureBasic
1
2
Dim fso As New FileSystemObject, ts As New TextStream
Set ts = fso.OpenTextFile("c:\test.txt", ForWriting)
Третий путь - вы можете использовать метод OpenAsTextStream с установкой флага ForWriting:
PureBasic
1
2
3
4
5
Dim fso As New FileSystemObject, fil As File, ts As TextStream
Set fso = CreateObject("Scripting.FileSystemObject")
fso.CreateTextFile ("test1.txt")
Set fil = fso.GetFile("test1.txt")
Set ts = fil.OpenAsTextStream(ForWriting)
Добавление данных к файлу

Когда текстовый файл создан, вы можете добавлять в него данные. Для этого необходимо:
  • открыть текстовый файл для записи данных;
  • записать данные;
  • закрыть файл.

Чтобы открыть файл вы можете использовать любой из двух методов: метод OpenAsTextStream объекта File или метод OpenTextFile объекта FileSystemObject.

Чтобы записать данные в открытый текстовый файл, используйте методы Write или WriteLine объекта TextStream. Единственное различие между Write и WriteLine - то, что WriteLine добавляет символы новой строки к концу строки. Если Вы хотите добавлять символы новой строки в текстовый файл без записи других символов, используйте метод WriteBlankLines.

Чтобы закрыть открытый файл, используйте метод Close объекта TextStream.
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
Sub Create_File()
  Dim fso, txtfile
  Set fso = CreateObject("Scripting.FileSystemObject")
  Set txtfile = fso.CreateTextFile("c:\testfile.txt", True)
  'Запись линии
  txtfile.Write ("This is a test. ")
  'Запись линии с символом newline
  txtfile.WriteLine("Testing 1, 2, 3.")
  'Запись трех символов newline в файл
  txtfile.WriteBlankLines(3)
  txtfile.Close
End Sub

Чтение файлов с помощью FSO
Для чтения данных из текстового файла используйте методы Read, ReadLine или ReadAll объекта TextStream:
Чтение определенного числа символов из файла - Read
Чтение строки целиком (но не включая символ новой строки) - ReadLine
Чтение текстового файла целиком - ReadAll

Если вы используете метод Read или ReadLine и хотите перейти к определенной части файла, воспользуйтесь методами Skip или SkipLine для пропуска определенного числа символов (или, соответственно, строк).

Полученный в результате использования этих методов текст может быть сохранен в символьной переменной и обрабатываться функциями Left, Right и Mid. Обратите внимание, что константа vbNewLine содержит символ или символы (в зависимости от операционной системы) перевода курсора на следующую строку (возврат каретки). Некоторые символьные переменные могут содержать в конце эти непечатаемые символы.
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Sub Read_Files()
  Dim fso As New FileSystemObject, txtfile
  Dim fil1 As File, ts As TextStream
  Set txtfile = fso.CreateTextFile("c:\testfile.txt", True)
  MsgBox "Writing file"
  ' Запись линии
  Set fil1 = fso.GetFile("c:\testfile.txt")
  Set ts = fil1.OpenAsTextStream(ForWriting)
  ts.Write "Hello World"
  ts.Close
  ' Чтение содержания файла
  Set ts = fil1.OpenAsTextStream(ForReading)
  s = ts.ReadLine
  MsgBox s
  ts.Close
End Sub

Перемещение, копирование и удаление файлов
FSO имеет два метода для перемещения, копирования и удаления файлов:
Переместить файл - File.Move или FileSystemObject.MoveFile
Скопировать файл - File.Copy или FileSystemObject.CopyFile
Удалить файл - File.Delete или FileSystemObject.DeleteFile

Следующий пример создает текстовый файл в корневой директории дисковода с:, пишет в него некоторую информацию, перемещает его в каталог, называемый \tmp, затем копирует его в каталог, называемый \temp и, наконец, удаляет копии из обоих каталогов. Чтобы этот пример корректно сработал, удостоверьтесь, что на диске c: в корневой папке существуют каталоги \tmp и \temp. (Для упрощения примера в него не встроена проверка этого условия. В реальной программе, конечно, необходимо сначала убедиться в существовании целевой папки и при ее отсутствии создать.)
PureBasic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Sub Manip_Files()
  Dim fso As New FileSystemObject, txtfile, fil1, fil2
  Set txtfile = fso.CreateTextFile("c:\testfile.txt", True)
  MsgBox "Writing file"
  txtfile.Write ("This is a test.")
  txtfile.Close
  MsgBox "Moving file to c:\tmp"
  ' Код обработки файла в корне C:\
  Set fil1 = fso.GetFile("c:\testfile.txt")
  ' Перемещаем файл в директорию \tmp
  fil1.Move ("c:\tmp\testfile.txt")
  MsgBox " Копируем файл в c:\temp"
  ' Копируем файл в \temp
  fil1.Copy ("c:\temp\testfile.txt")
  MsgBox "Удаляем файлы"
  ' Код получения текущих дерикторий файлов
  Set fil1 = fso.GetFile("c:\tmp\testfile.txt")
  Set fil2 = fso.GetFile("c:\temp\testfile.txt")
  ' Удаляем дайлы
  fil1.Delete
  fil2.Delete
  MsgBox "Все!"
End Sub
15
Елена
2439 / 788 / 24
Регистрация: 18.08.2009
Сообщений: 1,697
17.12.2009, 19:05 #7
Изменение начального значения поля счетчика (MDB)
Сведения в данном разделе относятся только к базам данных Microsoft Access (.mdb).В новой таблице, еще не содержащей записей, можно изменить начальное значение для поля счетчика, у которого в свойстве Новые значения (NewValues) задан тип Последовательные, на значение, отличное от 1. В таблице, содержащей записи, описанные ниже действия позволяют изменить значение счетчика в следующей новой записи.
  1. Если в исходной таблицы заданы параметры свойств, которые запрещают существование значений Null в полях, то эти свойства надо изменить. Сюда относятся следующие свойства, если для них указаны приведенные ниже значения:
    • свойство Обязательное поле (Required) поля, имеющее значение Да ;
    • свойство Индексированное поле (Indexed) поля, имеющее значение Да (Совпадения не допускаются);
    • свойство Условие на значение (ValidationRule) поля и/или записи, в котором указано условие, запрещающее существование значений Null в полях.
  2. Создайте временную таблицу, содержащую одно поле типа «Числовой». Задайте для него в свойстве Размер поля (FieldSize) тип Длинное целое и присвойте этому полю имя, совпадающее с именем поля счетчика, значение которого требуется изменить.
  3. В режиме таблицы введите в числовое поле временной таблицы значение, на единицу (1) меньшее, чем требуемое начальное значение для поля счетчика. Например, чтобы начать нумерацию счетчика с числа 100, введите в числовое поле значение 99.
  4. Создайте и выполните запрос на добавление для добавления временной таблицы в таблицу, содержащую поле счетчика, которое нужно изменить. http://office.microsoft.com/global/i...ZA790050001049Инструкции
    1. Создайте запрос, содержащий таблицу, записи из которой необходимо добавить в другую. http://office.microsoft.com/global/i...ZA790050001049Инструкции
      1. В окне базы данных нажмите кнопку Запросы http://office.microsoft.com/global/i...ZA060472631049 на панели Объекты, а затем нажмите кнопку Создать на панели инструментов окна базы данных.
      2. В диалоговом окне Новый запрос щелкните строку Конструктор, а затем нажмите кнопку OK.
      3. В диалоговом окне Добавление таблицы выберите вкладку, содержащую объекты, данные из которых будут использованы в запросе.
      4. Дважды щелкните объекты, которые нужно добавить в запрос, а затем нажмите кнопку Закрыть.
      5. Добавьте поля в строку Поле в бланке запроса] и, если необходимо, укажите условия и порядок сортировки.
      6. Чтобы просмотреть результаты запроса, нажмите кнопку Вид http://office.microsoft.com/global/i...ZA060446481049 на панели инструментов.
    2. В режиме конструктора запроса нажмите стрелку рядом с кнопкой Тип запроса http://office.microsoft.com/global/i...ZA060445671049 на панели инструментов и выберите команду Добавление. На экране появится диалоговое окно Добавление.
    3. В поле Имя таблицы введите имя таблицы, в которую необходимо добавить записи.
    4. Выполните одно из следующих действий. Если таблица находится в открытой в настоящий момент базе данных, выберите параметр в текущей базе данных.
      Если таблица не находится в открытой в настоящий момент базе данных, выберите параметр в другой базе данных и введите имя базы данных, в которой находится таблица, или нажмите кнопку Обзор, чтобы указать путь к базе данных. Можно ввести путь к базе данных Microsoft FoxPro, Paradox или dBASE, а также строку подключения к базе данных SQL.
    5. Нажмите кнопку OK.
    6. Перетащите из списка полей в бланк запроса поля, которые необходимо добавить или которые будут использоваться при определении условия отбора. Если все поля в обеих таблицах имеют одинаковые имена, то можно просто перетащить знак «звездочка» (*) в бланк запроса. Однако при работе с репликой базы данных придется добавлять все поля.
    7. Для поля с типом данных «Счетчик» выполните одно из следующих действий. http://office.microsoft.com/global/i...ZA790050001049Автоматическое добавление значений счетчика
      Для автоматического добавления значений счетчика не следует при создании запроса перетаскивать поле счетчика в бланк запроса.
      В этом случае при добавлении записей значения в поле счетчика вставляются автоматически. Первая добавленная запись получит значение на единицу большее, чем имела последняя ранее введенная в поле счетчика запись (даже если запись, содержащая в поле счетчика максимальное значение, была удалена).
      Воспользуйтесь этим способом, если поле счетчика в таблице, в которую добавляются записи, является ключевым, а исходная таблица содержит в поле счетчика значения, совпадающие со значениями в таблице-получателе.

      http://office.microsoft.com/global/i...ZA790050001049Сохранение в поле счетчика значений из исходной таблицы
      Для сохранения в поле счетчика значений из исходной таблицы перетащите при создании запроса поле счетчика в бланк запроса.
    8. Если в обеих таблицах выделенные поля имеют одинаковые имена, то соответствующие имена автоматически вводятся в строку Добавление. Если имена полей двух таблиц отличны друг от друга, нужно будет указать в строке Добавление имена полей таблицы-получателя.
    9. Для полей, перемещенных в бланк запроса, введите в ячейку Условие отбора условие отбора, по которому будет осуществляться добавление.
    10. Чтобы просмотреть записи, которые будут добавлены, нажмите кнопку Вид http://office.microsoft.com/global/i...ZA060446481049 на панели инструментов. Чтобы вернуться в режим конструктора запроса, снова нажмите кнопку Вид http://office.microsoft.com/global/i...ZA060446491049 на панели инструментов. Внесите в режиме конструктора необходимые изменения.
    11. Чтобы добавить записи, нажмите кнопку Выполнить http://office.microsoft.com/global/i...ZA060445871049 на панели инструментов.
  5. Удалите временную таблицу.
  6. Удалите запись, добавленную в исходную таблицу с помощью запроса на добавление.
  7. Если на шаге 1 были отключены какие-либо настройки, восстановите исходные значения свойств.
При вводе следующей записи в оставшуюся таблицу поле счетчика получит значение, на единицу (1) превышающее значение, введенное во временную таблицу.

http://office.microsoft.com/ru-ru/access/HP051887741049.aspx


Сброс значения поля счетчика в Access
В данной статье описывается сброс значения поля Счетчик в Access. Значение поля Счетчик в программе Access не сбрасывается автоматически при удалении нескольких или всех строк в таблице. Для сброса значения поля Счетчик и обновления значения Счетчик в указанной таблице необходимо выполнить определенные действия вручную.

Примечание. Перед выполнением следующих действий небходимо выполнить резервное копирование базы данных.

Сброс поля счетчика в отдельной таблице
Для сброса значения поля Счетчик можно использовать способ 1 или способ 2.

Способ 1

Можно выполнить сброс значения поля Счетчик, чтобы оно соответствовало одному из полей в таблице. В Microsoft Office Access 2003 или более ранних версиях выполните следующие действия.
  1. Удалите поле Счетчик из основной таблицы.

    Запомните имя поля Счетчик.
  2. Щелкните Запросы на левой панели. Дважды щелкните Создание запроса в режиме конструктора на правой панели.
  3. В диалоговом окне Добавление таблицы выберите основную таблицу. Нажмите кнопку Добавить, а затем — Закрыть.
  4. Дважды щелкните нужные поля в основной таблице в режиме таблицы, чтобы выбрать эти поля.
  5. Выберите нужный порядок Сортировка.
  6. В меню Запрос выберите команду Запрос на создание таблицы. В поле Имя таблицы введите имя новой таблицы и нажмите кнопку OK.
  7. В меню Запрос выберите команду Выполнить.
  8. Появится диалоговое окно со следующим текстом: Будет добавлено следующее число записей #. Нажмите кнопку Да, чтобы добавить записи в новую таблицу.
  9. В меню Файл выберите команду Закрыть. Нажмите кнопку Нет, чтобы закрыть окно Запрос на создание таблицы.
  10. Выберите Таблицы на левой панели. Щелкните новую таблицу правой кнопкой мыши и выберите Конструктор.
  11. В режиме Конструктор добавьте поле Счетчик и присвойте ему название поля, удаленного на шаге 1. Добавьте это поле Счетчик в новую таблицу и сохраните изменения.
  12. Закройте окно режима Конструктор.
  13. Измените название основной таблицы. Дайте новой таблице название основной.
В Microsoft Office Access 2007 выполните следующие действия.
  1. Удалите поле Счетчик из основной таблицы.

    Запомните имя поля Счетчик.
  2. Выберите вкладку Создать, затем выберите Конструктор запросов в группе Прочее.
  3. В диалоговом окне Добавление таблицы выберите основную таблицу. Нажмите кнопку Добавить, а затем — Закрыть.
  4. Дважды щелкните нужные поля в основной таблице в режиме таблицы, чтобы выбрать эти поля.
  5. Выберите нужный порядок Сортировка.
  6. На вкладке Конструктор выберите Создание таблицы в группе Тип запроса. В поле Имя таблицы введите имя новой таблицы и нажмите кнопку OK.
  7. На вкладке Конструктор нажмите кнопку Выполнить в группе Результаты.
  8. Появится следующее сообщение:В новую таблицу будет помещено следующее число записей: #.
    Нажмите кнопку Да, чтобы добавить записи в таблицу.
  9. Закройте запрос.
  10. Щелкните новую таблицу правой кнопкой мыши и выберите Конструктор.
  11. В режиме Конструктор добавьте поле Счетчик и присвойте ему название поля, удаленного на шаге 1. Добавьте это поле Счетчик в новую таблицу и сохраните изменения.
  12. Закройте окно режима Конструктор.
  13. Измените название основной таблицы. Дайте новой таблице название основной.
Способ 2

Для сброса значения поля Счетчик с помощью способа 2 выполните следующие действия.
  1. В Access 2003 и более ранних версиях удалите поле Счетчик из основной таблицы.

    Запомните имя поля Счетчик.
  2. Скопируйте структуру основной таблицы и создайте новую таблицу.
  3. Выберите Запросы на левой панели. Нажмите кнопку Создание запроса в режиме конструктора на правой панели.
  4. В диалоговом окне Добавление таблицы выберите основную таблицу. Нажмите кнопку Добавить, а затем — Закрыть.
  5. Для выбора полей дважды щелкните нужные поля. Выберите таким образом все поля, кроме поля Счетчик в режиме Таблица основной таблицы.
  6. В меню Запрос щелкните Запрос на добавление.

    Тип запроса будет изменен.
  7. В списке Имя таблицы выберите новую таблицу, созданную на шаге 2. Нажмите кнопку OK.
  8. В меню Запрос выберите команду Выполнить.
  9. Появится диалоговое окно со следующим текстом: В таблицу будет помещено следующее число записей: #. Нажмите кнопку Да, чтобы добавить записи в новую таблицу.
  10. В меню Файл выберите команду Закрыть. Нажмите кнопку Нет, чтобы закрыть окно Запрос на добавление.
  11. Выберите Таблицы на левой панели. Щелкните новую таблицу правой кнопкой мыши и выберите Конструктор.
  12. В режиме Конструктор добавьте поле Счетчик и присвойте ему название поля, удаленного на шаге 1. Добавьте это поле Счетчик в новую таблицу и сохраните изменения.
  13. Закройте окно режима Конструктор.
  14. Измените название основной таблицы. Дайте новой таблице название основной.
В Access 2007 выполните следующие действия.
  1. Удалите поле Счетчик из основной таблицы.

    Запомните имя поля Счетчик.
  2. Скопируйте структуру основной таблицы и создайте новую таблицу.
  3. Выберите вкладку Создать, затем нажмиьте кнопку Конструктор запросов в группе Прочее.
  4. В диалоговом окне Добавление таблицы выберите основную таблицу. Нажмите кнопку Добавить, а затем — Закрыть.
  5. Для выбора полей дважды щелкните нужные поля. Выберите таким образом все поля, кроме поля Счетчик в режиме Таблица основной таблицы.
  6. На вкладке Конструктор нажмите кнопку Добавить в группе Тип запроса. Тип запроса будет изменен.
  7. В списке Имя таблицы выберите новую таблицу, созданную в шаге 2, и нажмите кнопку OK.
  8. На вкладке Конструктор нажмите кнопку Выполнить в группе Результаты.
  9. Появится следующее сообщение: Будет добавлено следующее число записей #.
    Нажмите кнопку Да, чтобы добавить записи в таблицу.
  10. Закройте запрос.
  11. Щелкните новую таблицу правой кнопкой мыши и выберите Конструктор.
  12. В режиме Конструктор добавьте поле Счетчик и присвойте ему название поля, удаленного на шаге 1. Добавьте это поле Счетчик в новую таблицу и сохраните изменения.
  13. Закройте окно режима Конструктор.
  14. Измените название основной таблицы. Дайте новой таблице название основной.


Сброс поля счетчика в таблице со ссылками на другие таблицы
Приведенные ниже действия предназначены для сброса поля Счетчик для таблицы со ссылкой на одну таблицу. При наличии нескольких ссылок на таблицы эти действия необходимо выполнить для всех указанных таблиц.
  1. Удалите отношение между таблицами.
  2. Для поля Счетчик в основной таблице установите тип данных Числовой. Удалите ключевое поле.
  3. В основной таблице создайте новое поле с типом данных Счетчик. Сохраните таблицу.
  4. В указанной таблице создайте новое поле с типом данных Счетчик. Сохраните таблицу.
  5. Для создания запроса на обновление нового поля в указанной таблице в соответствие с полем Счетчик основной таблицы выполните следующие действия.
    1. В Access 2003 или более ранних версиях нажмите кнопку Запросы на левой панели. Нажмите кнопку Создание запроса в режиме конструктора на правой панели.

      Будет создан новый запрос.
    2. В диалоговом окне Добавление таблицы выберите основную и указанную таблицу. Нажмите кнопку Добавить для добавления основной и указанной таблиц. Нажмите кнопку Закрыть.
    3. Щелкните поле основной таблицы, которое ранее ссылалось на указанную таблицу. Перетащите поле на другое поле, ранее ссылавшееся на указанную таблицу.

      Будет создана связь между таблицами основе исходных связанных полей.
    4. В меню Запрос выберите Запрос на обновление.
    5. Дважды щелкните новое поле в указанной таблице, чтобы добавить его в список полей.
    6. В поле Обновление введите [Main TableName].[New AutoNumber field] для обновления значения нового поля в указанной таблице.
    7. В меню Запрос выберите команду Выполнить.
    8. Появится диалоговое окно со следующим текстом: Будет обновлено следующее число записей: #. Нажмите кнопку Да, чтобы обновить записи.
    9. В меню Файл выберите команду Закрыть. Нажмите кнопку Нет, чтобы закрыть окно Запрос на обновление.
    В Access 2007 выполните следующие действия.
    1. Выберите вкладку Создать, затем выберите Конструктор запросов в группе Прочее. Будет создан новый запрос.
    2. В диалоговом окне Добавление таблицы выберите основную и указанную таблицу. Нажмите кнопку Добавить для добавления основной и указанной таблиц. Нажмите кнопку Закрыть.
    3. Щелкните поле основной таблицы, которое ранее ссылалось на указанную таблицу. Перетащите поле на другое поле, ранее ссылавшееся на указанную таблицу.

      Будет создана связь между таблицами основе исходных связанных полей.
    4. На вкладке Конструктор нажмите кнопку Обновить в группе Тип запроса. Тип запроса будет изменен.
    5. Дважды щелкните новое поле в указанной таблице, чтобы добавить его в список полей.
    6. В поле Обновление введите [Main TableName].[New AutoNumber field] для обновления значения нового поля в указанной таблице.
    7. На вкладке Конструктор нажмите кнопку Выполнить в группе Результаты.
    8. Появится следующее сообщение:Будет обновлено следующее число записей: #.
      Нажмите кнопку Да, чтобы обновить записи.
    9. Закройте запрос.
  6. Удалите исходной связанное поле из основной и указанной таблицы.
  7. Присвойте полю Счетчик исходное имя.
  8. Снова создайте ключевое поле и связь между таблицами.
Эта процедура сбрасывает поле Счетчик и обновляет указанную таблицу в соответствие с верными основными значениями.


Поле Счетчик также можно сбросить при сжатии базы данных. Однако это не всегда работает в Access 2002 или более поздних версиях. Сжатие базы данных гораздо успешнее осуществляется в версиях Access 2000 и Jet 4.0 механизма баз данных Microsoft Jet. Для получения дополнительных сведений шелкните следующий номер статьи базы знаний Майкрософт: 287756 Значение поля AutoNumber не сбрасывается после сжатия базы данных Access

Для получения дополнительных сведений щелкните следующие номера статей базы знаний Майкрософт. 209696 Использование запроса добавления для установки первоначального значения поля счетчика (Эта ссылка может указывать на содержимое полностью или частично на английском языке)
94821 Использование запроса добавления для установки первоначального значения поля счетчика (Эта ссылка может указывать на содержимое полностью или частично на английском языке)
202121 Изменение первоначального значения и приращения по умолчанию в пользовательском интерфейсе невозможны (Эта ссылка может указывать на содержимое полностью или частично на английском языке)

Информация в данной статье относится к следующим продуктам.
  • Microsoft Office Access 2007
  • Microsoft Office Access 2003
  • Microsoft Access 2002 Standard Edition
  • Microsoft Access 2000 Standard Edition
4
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
17.12.2009, 22:14  [ТС] #8
Как создать свой счетчик (чтобы поле было не типа счетчик)?
A: Надо написать функцию, к которой обращаться либо в DefaultValue контрола (к сожалению, DefaultValue поля в таблице допускает только ограниченный набор стандартных функций), либо в программе, которая добавляет запись через рекордсет, либо в запросе на добавление. Ниже приведено несколько вариантов такой функции. Особое внимание надо уделить обработчику ошибок.

Вариант 1

Visual Basic
1
Nz(DMax(...),0)+1
Так можно нумеровать записи даже внутри группы, а не только насквозь через всю таблицу. Для этого надо правильно задать параметры DMax.

Правда, надо отдельно позаботиться о ситуации, когда два юзера обратятся к этому "генератору счетчиков" одновременно. На этот случай надо написать обработчик ошибок.

Вариант 2

Заводим отдельную таблицу с одним полем типа счетчик и без данных. Приводимая ниже процедура обращается к такой таблице и возвращает очередное значение для "нашего" счетчика. Внимание - файл, в котором сидит эта таблица, запрещено сжимать.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Function Cou() As Long
 
Dim ws As Workspace, db As Database
Dim rsCounter As Recordset
 
On Error GoTo errCou
Set ws = DBEngine(0)
Set db = CurrentDb
1
ws.BeginTrans
2
Set rsCounter = db.OpenRecordset("select * from tabCounter")
3
rsCounter.AddNew
Cou = rsCounter!nCounter
'Close without update!'
rsCounter.Close
4
ws.CommitTrans
5
Exit Function
 
errCou:
Select Case Erl
    Case 3
        rsCounter.Close
        Set rsCounter = Nothing
        ws.Rollback
        DBEngine.Idle DB_FREELOCKS
        Resume 1
    Case 2, 4
        ws.Rollback
        DBEngine.Idle DB_FREELOCKS
        Resume 1
    Case Else
        Resume Next
End Select
 
End Function

Подвариант: все-таки делать rsCounter.Update, тогда по виду этой таблицы будет сразу ясно, какое значение было выдано последним. Правда, в этом случае файл станет расти.

Еще подвариант: держать в этой таблице одну запись, в которой находится очередное значение счетчика, и вместо AddNew делать Edit и rsCounter!nCounter=rsCounter!nCounter+1, а потом соответственно Update.

Вариант 3 (от Гетца)

Держим в отдельной таблице очередное значение счетчика и каждый раз увеличиваем его на 1. Таблица блокируется на момент чтения и увеличения счетчика, а все, кто в нее будут в это время стучаться, спокойно ждут (см. обработчик ошибок adhGetNextAutoNumber_Err) освобождения таблицы.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
Function adhGetNextAutoNumber(ByVal strTableName As String) As Long
 
    On Error GoTo adhGetNextAutoNumber_Err
 
    Dim wrk As dao.Workspace
    Dim db As dao.Database
    Dim rstAutoNum As dao.Recordset
    Dim lngW As Long
    Dim lngX As Long
    Dim intRetryCount As Integer
    
    Randomize
    DoCmd.Hourglass True
    intRetryCount = 0
 
    Set wrk = dao.DBEngine.Workspaces(0)
    Set db = wrk.OpenDatabase(adhCurrentDBPath() & adhcAutoNumDb, False)
    Set rstAutoNum = db.OpenRecordset(strTableName & "_ID", dbOpenTable, dbDenyRead)
 
    rstAutoNum.MoveFirst
    rstAutoNum.Edit
    rstAutoNum!NextAutoNumber = rstAutoNum!NextAutoNumber + 1
    rstAutoNum.Update
 
    adhGetNextAutoNumber = lngNextAutoNum
 
adhGetNextAutoNumber_Exit:
    DoCmd.Hourglass False
    On Error Resume Next
    rstAutoNum.Close
    Set rstAutoNum = Nothing
    db.Close
    Set db = Nothing
    wrk.Close
    Set wrk = Nothing
    Exit Function
 
adhGetNextAutoNumber_Err:
    Select Case Err.Number
        Case adhcErrRI, adhcLockErrCantUpdate2, adhcLockErrTableInUse
            intRetryCount = intRetryCount + 1
            If intRetryCount > adhcLockRetries Then
                adhGetNextAutoNumber = -1
                Resume adhGetNextAutoNumber_Exit
            Else
                dao.DBEngine.Idle
                lngW = intRetryCount ^ 2 * _
                  Int((adhcLockUBound - adhcLockLBound + 1) * Rnd() + adhcLockLBound)
                For lngW = 1 To lngW
                    DoEvents
                Next lngW
                Resume
            End If
        Case Else
            MsgBox "Error " & Err.Number & ": " & Err.Description, _
             vbOKOnly + vbCritical, "adhGetNextAutoNumber"
            adhGetNextAutoNumber = -1
            Resume adhGetNextAutoNumber_Exit
    End Select
 
End Function


Как заставить счетчик начать выдавать значения начиная с некоторой заданной величины?
A1: Добавить в таблицу со счетчиком при помощи инсерта запись, в которой полю счетчика дается значение на 1 меньше, чем надо. Потом удалить эту запись. Способ работает только при условии, что этот счетчик этого или большего значения еще не выдавал. (Если таким образом дать счетчику отрицательное значение, то он начнет выдавать отрицательные значения, несмотря на то что уже выдавал значения, большие их. Играя на этом, можно добиться, чтобы счетчик выдавал любые значения, в т.ч. и те, которые уже были.)

A2: Сжать базу, в которой сидит таблица со счетчиком. Счетчик будет выдавать значения начиная с наибольшего из существующих +1. В некоторых версиях Аксесса это работает только при условии, что таблица со счетчиком пуста (и тогда счетчик начнет выдавать значения с 1).

A3: Начиная с Аксесса 2000, можно запустить запрос наподобие такого:

SQL
1
ALTER TABLE Таблица1 ALTER COLUMN ПолеСчетчик counter(1,1)


Может ли поле счетчика содержать повторяющиеся значения?
В принципе да. Этого несложно достичь, меняя состояние счетчика описанными способами. Однако если при этом возникнут нарушения ключа (вообще говоря, поле счетчика можно и не делать ключевым, но обычно все-таки принято делать), то записи просто не смогут добавляться. Каждая неудачная попытка добавить запись будет увеличивать значение счетчика на 1. Когда зона существующих значений будет пройдена, то записи опять смогут добавляться.


В таблице есть счетчик, но его значения идут не подряд, несколько чисел в середине отсутствуют. Как перезаполнить поле, чтобы дырок не было?
(Другой вариант вопроса. Счетчик показывает, что последняя запись в моей таблице имеет номер N, а реально записей меньше. Почему счетчик неправильно считает количество записей в таблице? Что это - баг или фича?)

A: Это нормальная ситуация. Если возникла необходимость, чтобы значения счетчика шли подряд, значит база была спроектирована неверно. Поле счетчика должно служить только для однозначной идентификации записей (и, возможно, порядка их занесения), юзер не должен видеть его значений, а если и увидит, то не должен возражать против тех значений, которые есть. Счетчик не служит для подсчета записей.


Как сымитировать счетчик в отчете?
Заводим текстбокс и задаем ему свойства:
Visual Basic
1
2
ControlSource = "=1"
RunningSum = Over All


Как сымитировать счетчик в запросе на добавление?
Пишем функцию примерно такого вида:
Visual Basic
1
2
3
4
5
6
7
8
9
10
Function MyFun(varDummy As Variant, Optional iStartValue As Variant) As Long
Static n As Long
If IsMissing(iStartValue) Then
    MyFun = n
    n = n + 1
Else
    n = iStartValue
    MyFun = True
End If
End Function
В запросе обращаемся к ней дважды:

# в части WHERE - с параметрами (чтоугодно,N), где N равно нужному начальному значению счетчика;
# в части SELECT - в качестве первого параметра передавать любое поле из таблицы, второй параметр не указывать.

Внимание: упрощать этот код, удаляя из него параметр, передаваемый в части SELECT, - нельзя. Без параметра функция будет вызвана только один раз, а не в каждой записи заново.


Как сымитировать счетчик в обычном запросе либо ленточной форме?
A1:
SQL
1
2
3
SELECT (SELECT SUM(1) FROM t AS p WHERE p.f<=p1.f), p1.f
FROM t AS p1
ORDER BY p1.f;
A2:
SQL
1
2
3
SELECT DCount("f", "t","f<=" & CStr(f)), f
FROM t
ORDER BY f;
Примечание 1. Поле f обязано быть уникальным.

Примечание 2. Способ 1 быстрее работает, но является необновляемым.

A3: В новых версиях Аксесса у формы есть свойство CurrentRecord.


Как получить значение счетчика только что добавленной записи?
A1: Если запись добавляется через рекордсет, то так:

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
rs.AddNew
переменная = rs!полесчетчика
...
rs.Update
 
'или
 
Set rs = ...OpenRecordset("...where 1=0") 'обязательно пустой рекордсет
rs.AddNew 'ровно один раз; при добавлении двух и более записей ничего не получится
...
rs.Update
rs.MoveFirst
переменная = rs!полесчетчика
 
'или
 
rs.AddNew
...
rs.Update
rs.Bookmark = rs.LastModified
переменная = rs!полесчетчика
A2: Более широкий круг применимости у такого способа:

Visual Basic
1
2
3
4
5
6
Dim rs As ADODB.Recordset 
Set rs = New ADODB.Recordset
CurrentProject.Connection.Execute "INSERT ..."
rs.Open "SELECT @@identity as cou", CurrentProject.Connection
переменная = rs!cou
rs.Close
Однако и этот способ имеет ограничения, а именно:

# работает либо через ADO, либо через DAO в Jet 4 и позже, и только с базами формата Аксесса 2000 и позже;
# возвращает значение только из записи, добавленной программно, но не через юзер-интерфейс.

A3: Для adp годится такая модификация того же способа:

T-SQL
1
SELECT SCOPE_IDENTITY() AS [SCOPE_IDENTITY]


Как создать одним запросом таблицу со счетчиком?
SQL
1
CREATE TABLE xx (id counter)


Источник
9
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
24.12.2009, 18:27  [ТС] #9
Хочу рассмотреть проблему защиты данных, находящихся в таблицах. Будем рассматривать файл-серверный вариант размещения базы.

Прежде, чем начнем разговор о защите, Вы должны ясно представить себе, от чего вы хотите защитить свои данные. Защиты бывают разных уровней и сложностей. И может быть выполнение требования «максимально защитить все данные» превысит по трудоемкости разработку и отладку самой базы. И помните, что один человек сделал, другой завсегда сломать может. И никакая защита не спасет от обыкновенного разгильдяйства. Я встречал случаи, когда логин и пароль доступа писали на бумажке, а затем эту бумажку клеили на монитор, «чтобы не потерять». И это не анекдот. Дело в том, что рядовому сотруднику фирмы/отдела чаще всего нет никакого дела до защиты информации. Его задача – отработать положенные часы, причем с наибольшим комфортом для себя. Отсюда и выходит: раздаешь пароли доступа КАЖДОМУ сотруднику, а они их пишут на бумажке (общим списком) и кладут под стекло. Такое «безобразие» обычно заканчивается тем, что кто то чего то не туда ввел/удалил. Начинаются разборки – и тут до оператора доходит, что если бы он не разглашал свой пароль, то, стало быть, никто не смог бы влезть в базу и «ковыряться» там от его имени. Отсюда вывод – защита базы, дело РУКОВОДИТЕЛЯ, а не операторов. Рассмотрим теперь способы защиты. Есть несколько уровней и способов защиты.

Административный метод
Позволяет защитить от несанкционированного копирования самой части базы с таблицами. Из компьютеров изымаются пишущие CD/DVD приводы, FDD, Zip и JAZZ, магнитооптика, USB закрываются программно системным администратором. Все операции записи на носители может выполнять только определенный человек. Если есть выход в и-нет, то соответствующе настраивается прокси-сервер. У пользователей удаляются полные версии Access и устанавливаются Run-time версии, отбираются права администратора. Такую ситуацию сейчас можно увидеть на многих фирмах с устоявшейся структурой и налаженной работой, и где персональные компьютеры – действительно персональные, а не как шутили ранее - «персональный компьютер коллективного пользования.

Иногда, к сожалению, административная защита превращается в фарс: «опломбировали» (заклеили) бумажками USB, на КПП охране дали указание проверять входящих/выходящих на наличие дискет (подумать только, какой архаизм – воровать дискетами), дисков… А многие спокойно ходят с мобильниками, в которых встроена Flash – карта. Такой уровень «защиты» показывает, что ей занимается человек весьма далекий от программных дел. Обычно такая картина наблюдается на госпредприятиях. Вообще, в отделах, отвечающих за защиту, не мешало бы повесить такой плакат:

Если информация записана – значит, ее можно прочитать, если ее можно прочитать – можно и скопировать, если можно скопировать – можно и украсть.


Маскировка базы
Как я писал ранее, разговор идет о разделенной базе данных. Часть с таблицами обычно хранится на сервере. И все пользователи должны иметь к ней доступ. Обычно на сервере создается каталог share (имя может быть любым) через который пользователи обмениваются файлами, где хранятся документы общего пользования и т.п. Никто не запрещает создать подходящий каталог и замаскировав его под служебный, присвоив какое-либо высокоумное название. Поместить в него базу данных (обычно, уже хорошо проработанная и долго эксплуатированная система обрастает кучей дополнительных каталогов, файлов, шаблонов и т.п.) и присвоить ей расширение, отличное от MDB. При подключении (линковании) таблиц Вы указываете точный путь и имя базы данных. И Access всё равно, как называется файл, главное, чтобы совпадала структура. В своё время, в Донецке, мне пришлось столкнуться с системой «Акцент» (бухгалтерская программа). Она была написана на VC, а вот в качестве хранилища данных в ней использовались MDB-файлы, с расширением – acc. Я встречал предложения вообще менять заголовок файла, а перед линковкой подставлять правильный. Но я бы не советовал такого делать. Операции прямой записи некоторые программы-сторожа (антивирусные мониторы) определяют как вирусные атаки и блокируют.

Кроме того, в многопользовательской среде, достаточно подключиться к базе с таблицами одному из клиентов, как измененный заголовок будет восстановлен. Для того, чтобы при простом просмотре клиентской части нельзя было определить путь к базе с таблицами, путь шифруется и восстанавливается только в момент самого линкования. Для того, чтобы нельзя было скопировать линки с клиентского модуля, рекомендуется в конце работы отключать все прилинкованные таблицы, а в начале – подключать. Но это хорошо для неработающего модуля. Стоит только запустить клиентскую часть, как линки на таблицы с данными будут восстановлены. А дальше можно уже подключаться из чистой базы к работающему клиентскому приложению и копировать себе линки на таблицы. Чтобы этого не происходило, можно использовать вспомогательные программы-стартёры. Например,- ReleaseUpdate (sd_ReleaseUpdate20.zip). Она проверяет наличие обновлений клиентской части, если они есть, то обновляет клиентскую часть, и запускает её на выполнение. Клиентскую часть можно расположить где-нибудь в Program Files, в специальном каталоге, а путь к ней, находящийся во внутренних таблицах программы ReleaseUpdate, можно зашифровать. Есть и другие готовые аналогичные программы. Например – MDBStarter (mdbstart.zip).

На одном из предприятий мне показывали следующую систему. На сервере лежал каталог с общим доступом и названием типа SystemControlFS. Пользователи не могли там ничего удалить. В нем была куча файлов и каталогов и файл SystemControlFS.exe. При попытке его запустить выдавалось сообщение, что у вас нет администраторских прав. База данных была замаскирована под один из вспомогательных файлов.

ПРЕДУПРЕЖДЕНИЕ. Никогда не присваивайте базе расширения, зарезервированные для временных файлов. Иначе программа очистки винчестера может его удалить. Не присваивайте расширения мультимедиа файлов. Иначе пользователи из любопытства всё время будут пытаться его запустить, чтобы глянуть, что там админ прячет на сервере?


Маскировка таблиц и полей
Предположим, что злоумышленнику удалось обойти вашу защиту и добраться до таблиц. Как быть в этом случае? Здесь тоже можно подпортить «хакеру» немного крови. Как Вы называете таблицы? Русские версии Access понимает русские названия и поначалу таблицы имеют такие имена; Адрес организации, Поступление Товара, Транспортные накладные и т.п. Очень скоро разработчик приходит к пониманию, что пробелы в названиях сильно усложняют жизнь, и появляются названия АдресОрганизации, ПоступлениеТовара, ТоварноТранспортныеНакладные… Еще через некоторое время появляются таблицы с именами: Sotrudniki, Tovar, Otdel… И в конце концов появляются названия tblAdressOrg (или tbAdressOrg), tblOtdel, tblZarplata… То же самое происходит и с именами запросов, форм, макросов, отчетов, а так же с названиями полей в таблицах и контролов на форме. Для большей читабельности базы, заполняются параметры «Описание» таблиц, запросов, форм, отчетов, макросов, полей.

А теперь представьте себе такую картину. Вы открываете базу, а там Table01, Table02, Table03…. Form01, Form02…. Report01, Report02… Поля в таблице имеют наименование Field01, Field02… В общем Вы меня поняли. Но для этого у Вас на компе или на листочке всё должно быть расписано подробнейшим образом. Имя таблицы, её назначение, имя поля – характер информации. Это потребует дополнительных затрат рабочего времени и большей организованности в работе. Не все на это легко согласятся.

А как же связи между таблицами? Открыв схему данных можно легко отследить связи между таблицами и тогда… В книгах и на форумах высказывалось много соображений про полезность и необходимость установки связей между таблицами. И сохранение целостности данных, и каскадное удаление записей, и увеличение скорости выполнения запросов и т.д. и т.п. Я не буду возражать насчет полезности связей, но без них можно обойтись. Пусть меня ругают и тыкают в меня пальцем, но я скажу, что создать довольно сложные приложения на Access можно и без создания схемы данных. Я это говорю из личного опыта. Но при этом все действия по сохранению целостности базы, удалению данных, разруливанию критических ситуаций Вы берете на себя. Это дополнительный код, это более тщательное программирование, дополнительный контроль при некоторых операциях (например – удалении). Более тщательный порядок при работе с таблицами. Всё это дополнительные затраты, но всё это не так сложно, как кажется на первый взгляд. А схему данных можно сделать и на бумаге. (Я так и делал).

А теперь, критические замечания. Про неудобство составления запросов и работы с рекордсетами, я уже писал. И про дополнительные сложности в программировании при отсутствии схемы данных – тоже. А вот про то, что текст всех запросов можно спокойно просмотреть даже в MDE файле об этом не упоминал. Даже то, что формы нельзя править, не является препятствием, для определения запроса, на котором основана форма. Даже если вы вручную набрали текст в поле «Источник данных» не спасает его от просмотра через панель (форму) «Свойства». Терпеливый пользователь, посидев с бумагой и ручкой, может восстановить схему данных.


Шифрование содержимого полей в таблицах
Здесь необходимо уточнить. Можно шифровать всю базу данных, а можно шифровать содержимое отдельных полей в таблицах. Рассмотрим для начала вторую возможность.

Этот способ защиты не плох. Во всяком случае, появляется реальная надежда, что-то спасти. Однако есть ряд ограничений. Шифровать следует только символьные поля или поля типа MEMO. Немного подумав, Вы сами поймете, почему так. Ну, хотя бы, при шифровании числовых полей, Вы можете получить в результате нечисловое значение. Впрочем, и это легко обходится. Я встречал варианты, когда счетчик записи использовался для шифрования числовых данных. Например, складывался с нужным числом. Или из счетчика бралась последняя цифра и добавлялась к числу. Но шифровать числовые данные допустимо только в особых случаях, когда их значение может быть однозначно привязано к определенному объекту или действию. В остальных случаях достаточно шифровать символьную информацию. Да и то выборочно. Например, названия клиентов, их адреса, контактные телефоны, реквизиты банковских счетов, фамилии и должности представителей заказчика (клиента). В общем, в зависимости от требований, шифроваться должно то, что однозначно позволяет идентифицировать запись.

Чем и как можно шифровать? Всем, чем угодно и как угодно. Здесь всё зависит от Вашего умения и опыта. Можно написать собственную функцию. Можно использовать специальные библиотеки. Например, clSample.zip. Можно сочетать приятное с полезным, не шифровать, а сжимать содержимое поля, используя библиотеки архивирования данных. Например, zlib123-dll.zip. А если Вы горите желанием, то и сами можете разработать подпрограмму сжатия. Но не стоит без нужды усложнять алгоритм шифрования, ведь перед отображением и обработкой данных их необходимо дешифровать. А на это необходимо время. И чем больше полей у Вас зашифровано, чем навороченнее алгоритм шифрования, тем больше времени на это уходит.

Ну, а теперь, как всегда, переходим к недостаткам этого метода. О том, что на это уходит время, я упоминал. Нельзя напрямую вводить в таблицы и формы данные, подлежащие шифрованию. Приходится делать для ввода и редактирования записей, содержащих шифрованные или сжатые данные, специальные формы. Но в некоторых случаях это даже к лучшему. Можно разрешить доступ к таким формам только определенным пользователям, с соответствующими привилегиями. Если Вы используете самописные функции (функции собственной разработки), то алгоритм шифрования и ключ содержатся в программе, а значит, есть и потенциальная уязвимость. В этом случае рекомендуется эти подпрограммы вынести в отдельный модуль. Если у пользователя клиентская часть будет в формате MDE, то он не сможет определить, какой файл подключен по References. Конечно, под отладчиком можно определить, какая библиотека (функция, класс) отсутствует. Для этого потенциальный взломщик должен иметь под рукой и клиентскую часть базы и часть с таблицами. И это уже квалификация не рядового пользователя. Если Вы используете библиотеки DLL, то здесь могут возникнуть вопросы с их установкой и регистрацией. Но в и-нете можно найти примеры, как можно установить и зарегистрировать DLL из самой базы Access. Кроме того, установку DLL и OCX можно возложить на программу-инсталятор клиентского приложения (если она у Вас есть). В конце-концов в и-нете много бесплатных программ для создания инсталляционных пакетов - например, InnoSetup. Потратив некоторое время, вы можете создать свой инсталляционный пакет, предназначенный для установки необходимых библиотек.


Защита на уровне доменных политик
На одном из форумов по Access я встретил такую заметку: «Всю свою трудовую историю работы с Аксесом, был твёрдо уверен, что защитить ФС (файл-сервер) Аксеса (mdb\mde) в сети (да и не только Аксеса, а вообще ФС) от несанкционированного доступа толком невозможно. Пока один очень сильный админ у моего клиента не продемонстрировал мне такую штуку. Файл сервер, Аксес, домен, АД, шара (полный доступ, т.к. это требуется для ФС), приложения на клиентских ПК (более 20) работают с файлом как обычно, штатно прилинкованные таблицы. Но... Ни в сети, ни в консоли, даже зная путь к шаре и имена файла, я не смог скопировать (дёрнуть) ф-л БД с сервера, ни открыть никакой вменяемой программой - призрак. Тыкался, тыкался... Уп-с. Чего он там намудрил с политиками - не знаю, не кололся. Но факт, я не смог получить доступ к самому файлу БД. При этом админ работал штатными средствами виндового сервера. После этого случая я задумался. О жизни, о админах и о технологиях ФС, одной из острых претензий к которой у меня была "незащищаемость" хранилища БД в сети. Если бы мне это рассказали ДО этого случая, если бы я сам не пытался безуспешно "ломануть" свою же АСУ, не поверил бы.» Подробности не были раскрыты, но высказывалось предположение, «Как версия: например, в Windows зашёл пользователь user1, у которого нет прав на доступ к сетевому каталогу с базой, а приложение запускалось с правами другого пользователя user2 (через runas или указан в свойствах ярлыка), у которого есть такие права.». Я не являюсь специалистом по администрированию Windows, но из личного опыта расскажу следующее. Когда возникла необходимость мне работать с Developer SQL Server, то наш админ установил его у меня на компе, причем так, что я мог свободно работать с базами, которые находились локально тут же на компьютере, знал раздел, где они лежали, но не мог в него зайти.


Защита с использованием пароля БД
Данный способ защиты позволяет установить пароль на открытие БД, для всех пользователей. Для его создания необходимо открыть файл БД в "монопольном" режиме и выбрать пункт меню Сервис / Защита / Задать пароль базы данных. Для работы с такой базой данных в MS Access потребуется вводить пароль. Вот пример работы с файлом БД, используя DAO или ADO.

Visual Basic
1
2
3
4
5
6
7
8
9
10
11
Public Sub TestDAO()
    Dim mWS As DAO.Workspace
    Dim mDB As DAO.Database
    Set mWS = DBEngine.Workspaces(0)
    Set mDB = mWS.OpenDatabase ("C:\a97.mdb", True, True, ";pwd=123")
End Sub
 
Public Sub TestADO()
    Dim CnDB As New ADODB.Connection
    CnDB.Open "Provider=Microsoft.Jet.OLEDB.4.0" & ";Data Source=C:\a97.mdb" & ";Jet OLEDB:Database Password=123"
End Sub
Это тоже не самый надёжный способ защиты баз данных. Существует достаточное количество бесплатных и платных утилит, отображающих пароль. В том числе доступны исходники кода на VB позволяющие прочитать такой пароль. В прочем не всё так плохо.
Дело в том, что некоторые разработчики считают, что кроме английского языка, других языков не существует. Достаточно включить в пароль русские буквы, чтобы привести в ступор пользователя, который использует такие программы. Да, они вроде бы и вскрывают пароль, но то, что они выдают в качестве пароля, разобрать невозможно.

Продолжим игры с паролем базы данных. Например, можно использовать в пароле непечатные символы. В первую очередь этот способ нацелен на противодействие определению паролей с помощью специальных программ. Стандартный способ установки и использования пароля БД подразумевает его ввод с клавиатуры в диалоговом окне. Если стока пароля содержит непечатные символы, то они не будут корректно отображены программой открывающей пароли БД. С другой стороны этот пароль нельзя ввести в диалоговом окне при открытии БД в MS Access.

Если бы пароль содержал символы табуляции, Esc или Enter, то стандартным образом Вы бы не смогли их ввести в окошко ввода пароля. Способ основан на том, что пароль БД формата Access 2000 и 2002-2003 - текстовая строка в формате Unicode (в Access 97 – ANSI). При этом нет ни каких ограничений на её содержимое. В спецификации баз данных и в справке по DAO 3.60 указано, что максимальное число символов в пароле - 14. Но на самом деле их может быть 20. При этом и сам Access 97 не допускает ввода строк пароля более 14 символов. В спецификации Access 2003 также сказано про 14 символов, но программа допускает ввод всех 20. Также возможно использование непечатных символов, что приводит большинство программ взламывающих пароли в ступор.

Для установки такого пароля потребуется применить специальную программу, использующую метод CompactDatabase библиотек ADOX или DAO. Но, как говорится, против всего можно найти лом. И такая защита вскрывается.

Во-первых, можно воспользоваться программой AccessRecovery, которая создаёт новый файл без защиты и переносит в него таблицы, запросы, формы, макросы, отчеты и код модулей.

Во-вторых, можно попытаться определить пароль БД с помощью специальных программ.

В-третьих, можно узнать пароль, проанализировав код программы в отладчике. Каков бы ни был пароль, он всё равно передаётся как текстовая строка в методе открытия БД. При наличии определённого опыта - это не очень сложная задача.

Узнать или изменить пароль БД можно, не прибегая к помощи специальных программ. В Access 97 пароль получается сложением по XOR пароля с 20 байтной последовательностью. Значения этих байт можно получить из любого не защищённого паролем mdb файла. Начиная с Access 2k, в связи с использованием Unicode, для хранения 20 символов пароля отведены 40 байт. При шифровании также используется сложение по XOR, но для получения последовательности байт соответствующей пустому паролю необходимо создать файл с датой исследуемой БД. Полученные байты можно вписать в исследуемый файл и обнулить пароль, либо сложить их с аналогичными байтами исследуемого файла и получить значение пароля. Но всё это уже требует наличие определенных знаний и опыта, так, что есть шансы на то, что любопытному пользователю надоест экспериментировать.


Шифрование/Дешифрование базы средствами Access
Вот что я нашел про кодирование/раскодирование баз данных Access в книге Access 2002. Разработка корпоративных приложений П.Литвина, К.Гетца и М.Гунделоя.

Как бы хорошо не была защищена база данных Jet, любой мало-мальски сообразительный хакер может при помощи низкоуровневого дискового редактора и получить доступ к её содержимому. Поэтому серьезная защита баз данных предполагает ещё и их шифрование. Конечно, взлом баз данных – дело не самое обыденное, но искатель приключений всегда может найтись. Само по себе шифрование базы данных ещё не гарантирует её надежной защиты, но всё же препятствует её просмотру средствами, внешними по отношению к Access и Jet.

Зашифровать и дешифровать базу данных могут только её владелец и члены группы Admins. Для шифрования Jet использует алгоритм RSA (назван по первым буквам фамилий его изобретателей: Rivest, Shamir, Adelman) с ключом на основе идентификатора рабочей группы. Для шифрования и дешифрования предназначена команда Access Tools > Security .> Encrypt / Decrypt Database.

У шифрования базы данных имеется два негативных побочных эффекта. Во-первых, снижается её быстродействие – по оценкам Microsoft, процентов на 10-15. Во-вторых, зашифрованную базу данных нельзя сжимать такими программами, как PKZip, LHA, Stacker и DriveSpace. Точнее, сжимать можно, только в этом нет смысла – её размер уменьшится незначительно.

Вот, что удалось ещё нарыть на сайте Microsoft:
Шифрование базы данных — это простейший способ защиты. При шифровании базы данных ее файл сжимается и становится недоступным для чтения с помощью служебных программ или текстовых редакторов.

Шифрование незащищенной базы данных неэффективно, поскольку каждый сможет открыть такую базу данных и получить полный доступ ко всем ее объектам.

Шифрование обычно применяется при электронной передаче базы данных или сохранении ее на дискету, кассету или компакт-диск. Шифровать-расшифровывать базу может либо хозяин базы, либо пользователь с администраторскими привилегиями и разрешением загружать базу в монопольном режиме.

Немного потыкал клавиши. В шифрованную базу можно добавлять записи, а имеющиеся - изменять. Шифрованную базу можно сжимать. Таблицы из шифрованной базы можно подлинковывать.

Пароль на базу не шифруется. Тело базы шифруется начиная с адреса 1000h. При просмотре тела базы разными вьюерами там действительно ерунда. Программы типа AccessFix не могут ничего из базы выдрать. (по крайней мере версии 3.70). Они там просто ничего не находят. Объекты из шифрованной базы можно импортировать в другую базу и они уже будут не шифрованные.

Вывод, шифровать стоит базу, уже защищенную стандартными средствами при помощи MDW.

На что не смог найти ответа:
1. можно ли к шифрованной базе подключиться из других клиентов - VB, Delphi, VC... (скорее всего можно)?
2. в случае краха, какова вероятность восстановления шифрованной БД?
Об алгоритме шифрования RSA можно прочитать вот здесь http://ru.wikipedia.org/wiki/RSA
А об его стойкости - http://www.bugtraq.ru/library/crypto/rsa.html
Защита при помощи терминального доступа к серверу
Практически непрошибаемая защита. И клиентская часть и база с таблицами находится на сервере. У клиента на компьютере эмулируется терминал сервера. Словно ты за ним сидишь (в смысле, за сервером). Можно настроить терминальный доступ так, что при запуске требуемой задачи (по ярлыку), запроса соответствующих паролей доступа к системе, сразу грузится требуемая база. При закрытии базы терминал закрывается. В самой базе прописана защита от шифта, отключены все стандартные Access-овские меню и горячие клавиши, отключено окно базы. И ничего пользователь ни затереть, ни скопировать не может. Ни открыть напрямую таблицы, ни получить доступ к закрытым для него формам и отчетам. Ещё терминальный доступ называется, по-моему, удаленным рабочим столом.

Недостатки этого способа – вся обработка данных ложится на сервер, зато в качестве клиентов можно использовать слабые машины.

Защита от шифт
Часто возникает необходимость закрыть доступ пользователям к окну проекта Access. Причины могут быть разные:

1. Любопытные пользователи стали «лазить» по базе и удалили макрос или «отредактировали» запрос (такое возможно ведь и в случае c .mde)
2. Вы решили продать свою программу. Чем меньше покупатель будет видеть не нужных ему элементов, тем лучше (см. п. 1)
3. Скрытие окна проекта позволяет сделать приложение более удобным в работе.

Простейшим вариантом решения проблемы может быть скрытие окна базы данных через стандартные настройки: Сервис – Параметры запуска – убрать галочку «окно базы данных». Однако, такую защиту столь же просто убрать, удерживая при запуске приложения Shift. Как же блокировать такую возможность?

Для построения интерфейса защиты создадим два макроса: AutoExec, AutoKeys. AutoKeys перехватывает нажатие клавиш на клавиатуре. Чтобы он их перехватывал, он должен называться AutoKeys (зарезервированное имя в Access). Еще один важный момент - в меню Сервис – Параметры запуска уберем все галочки, иначе обойти защиту от Shift станет весьма просто: Окно - Отобразить - Окно БД. Если же отключить все меню, то в пункте меню "Окно" будут выводится только режимы расположения окон, а окно базы выводится не будет.

В макросе AutoExec дадим команду на запуск формы FrmStart, в макросе AutoKeys – формы ВклОткШифт. Причем форма ВклОткШифт будет запускаться при нажатии комбинации клавиш Ctrl + Q. Для этого в конструкторе зададим имя макроса - ^Q.

Зачем так мудрено? Дело в том, что если мы просто зададим запуск формы в Сервис – Параметры запуска, то при включении защиты от Shift будет открываться пустое окно Access. Мы закроем базу вообще для всех, в том числе и от себя! Для всякого замка должен быть ключ: им и выступает форма ВклОткШифт - через нее устанавливается и снимается защита. А если ее сделать скрытой (см. ниже) и запускать через макрос (комбинацию клавиш) – мы еще больше запутаем любопытных юзеров. Само включение происходит через свойство базы

Visual Basic
1
DBS.Properties("AllowBypassKey") = True (или False)
В зависимости от значения пароля, введенного в поле формы «ВклОткШифт» этому свойству присваивается True или False. Затем база закрывается (чтобы изменения вступили в силу)

Visual Basic
1
DoCmd.Quit acPrompt
Итак, проведем испытание:

Запускаем наше приложение, удерживая Shift – открывается стартовая форма, окно проекта закрыто. Жмем Ctrl + Q, вводим 1234, жмем «Ввод». База закрывается. Снова щелкаем по базе, удерживая Shift – открывается стартовая форма, окно проекта открыто! И так делаем, пока не надоест.

А теперь по поводу «скрытый объект». Есть еще одна возможность заморочить пользователя. Дело в том, что в Access есть три варианта отображения объектов:

Нормальный режим (в окне базы данных не отображаются скрытые и системные объекты) установлен по умолчанию

Режим отображения скрытых объектов (в окне базы дынных не отображаются системные объекты)

Режим отображения системных объектов (отображаются все объекты)

Системный объект – это встроенный объект базы данных, определенный как системный, например таблица "MSysIndexes", или системные объекты, определенные пользователем. Для определения системного объекта необходимо, что бы его имя начиналось с символов USys. Например, добавьте к названию формы, таблицы, отчета USys – и они тут же «исчезнут», станут скрытыми, но обращаться к ним из приложения можно так же, как обычно.

Чтобы увидеть их, нужно сделать следующее:

Сервис – Параметры – Вкладка вид. В группе Отображать выберите требуемый вариант – поставьте (уберите) галочку «Скрытые объекты», «Системные объекты» и т. д.

Многих пользователей такая «защита» способна будет сбить с толку: даже сумев открыть приложение через Shift, они с удивлением обнаружат, что какой то формы или таблицы там нет, хотя при работе она видна. Но на профессионалов, конечно, такая уловка не подействует – разумеется, они знают о свойствах объектов базы данных. Но, если учесть, что большинство любопытных чаще всего бросают попытки «ковыряться», если у них не получилось с первого раза, то такая «защита» заслуживает внимания.

Выводы:

1. Защиту от Shift можно применять только при условии, что база преобразована в .mde. В противном случае ее легко обойти, сделав простой импорт всех объектов в новую базу. В .mde как известно без декомпиляции (взлома) невозможно сделать импорт общих модулей, форм и отчетов – самого ценного содержимого базы.
2. Если вы разрабатываете приложения на своей работе, то обычно лучший способ защиты – поговорить «по душам» с пользователями (и с начальством). Защита от Shift будет служить подобно реечному замку на гараже – при желании легко вскрывается, но не будь его, гараж обокрали бы еще быстрее.
3. Обычно защиту от Shift применяют в комплексе с другими методами: привязка к компьютеру, вход по паролю, шифрование данных и т. д.

Пример, как это все работает: Sift.zip


Запуск приложения через форму авторизации
В этой статье рассмотрим один из способов защиты приложения Access. Речь пойдет о входе в базу через ввод пароля, или говоря иначе - авторизация. В Access предусмотрена возможность задать пароль на базу данных: Сервис – Защита – Задать пароль базы данных. Однако сам пароль хранится в системном реестре в незашифрованном виде, и чтобы открыть такую защищенную базу, достаточно лишь зайти в реестр и прочитать его. Мы же попробуем создать аналогичный интерфейс, но уже с зашифрованным паролем, причем сделаем так, чтобы при попытке открыть форму, если пользователю удалось войти в базу, минуя стартовую форму авторизации, база аварийно закрывалась.

Для этого нам понадобится в служебной таблице, например tAdminCop, завести поле Password, в котором будем хранить пароль, а так же модуль шифрования пароля – AdminPassword.

Схема авторизации следующая:

При старте приложения запускается форма авторизации formAdmPassword, в которой вводим пароль

Пароль считывается, шифруется и сравнивается с зашифрованным паролем в поле таблицы tAdminCop

Если пароли совпадают, то открывается стартовая форма приложения, если нет – выход из приложения.

В модуле Constants задана константа логического типа. При правильном пароле она принимает значение True, при ложном (по умолчанию) – соответственно False. В событие формы frmStart есть такая процедура:

Visual Basic
1
2
3
4
5
     Private Sub Form_Open(Cancel As Integer)
          If flgEnabled = False Then
               DoCmd.Quit acPrompt
          End If
     End Sub
Как видно, если flgEnabled = False, то, стало быть, выход из приложения. Таким образом, и делается невозможность открытия формы без ввода пароля. Если аналогичные процедуры повесить на остальные формы, отчеты, то единственной лазейкой для "врагов" останутся только таблицы, у которых, к сожалению, нет никаких событий, которые можно бы было перехватить. Единственной защитой для них будет скрытие окна приложения и установка защиты от Shift.
Очевидно, что такая авторизация эффективна лишь в том случае, когда "врагам" нет хода к исходному коду модулей, иными словами база преобразована в формат .mde. Вообще, основа любой защиты приложений Access – это .mde формат. Действительно, вздумай Вы защищать подобным образом .mdb, любой мог бы просто открыть модуль Constants и прописать там

Visual Basic
1
Public Const flgEnabled = True
И все, никакой защиты.

Защита шифрованием пароля будет зависеть от сложности шифрования. Я показал лишь простейший пример (модуль AdminPassword). Вообще, стоит поискать в Интернете, или попытаться придумать самому более хитрый (стойкий) алгоритм шифрования.
Итак, проведем испытание:

Запускаем приложение. Появляется форма авторизации. Вводим 123456, жмем ввод – открывается стартовая форма. Теперь попробуем открыть форму frmStart без ввода пароля. Запускаем приложение, удерживая Shift – открывается окно проекта Access. Пытаемся запустить frmStart – приложение закрывается.
Если теперь добавить в нашу программу защиту от Shift, то приложение станет еще более «неприступным».

Используя защиту от Shift и вход через форму авторизации, можно здорово попортить нервы всем любителям лазить куда не следует. Но допустим, Вы решите установить (продать) свою программу кому - либо. Как сделать так, чтобы он не смог распространять ее без Вашего ведома? Иными словами, как организовать сервис регистрации программы?

Пример, как это все работает: Password.zip

Дмитрий Сонных (aka Joss)
15
БурундукЪ
9555 / 2556 / 83
Регистрация: 17.02.2009
Сообщений: 10,364
30.12.2009, 15:58  [ТС] #10
Лучший ответ Сообщение было отмечено ildwine как решение

Решение

Теория нормальных форм
Функциональные зависимости
Реляционная база данных содержит как структурную, так и семантическую информацию. Структура базы данных определяется числом и видом включенных в нее отношений, и связями типа "один ко многим", существующими между кортежами этих отношений. Семантическая часть описывает множество функциональных зависимостей, существующих между атрибутами этих отношений. Дадим определение функциональной зависимости.

Определение:
Если даны два атрибута X и Y некоторого отношения, то говорят, что Y функционально зависит от X, если в любой момент времени каждому значению X соответствует ровно одно значение Y.

Функциональная зависимость обозначается X -> Y. Отметим, что X и Y могут представлять собой не только единичные атрибуты, но и группы, составленные из нескольких атрибутов одного отношения.

Можно сказать, что функциональные зависимости представляют собой связи типа "один ко многим", существующие внутри отношения.

Некоторые функциональные зависимости могут быть нежелательны.

Определение:
Избыточная функциональная зависимость - зависимость, заключающая в себе такую информацию, которая может быть получена на основе других зависимостей, имеющихся в базе данных.

Корректной считается такая схема базы данных, в которой отсутствуют избыточные функциональные зависимости. В противном случае приходится прибегать к процедуре декомпозиции (разложения) имеющегося множества отношений. При этом порождаемое множество содержит большее число отношений, которые являются проекциями отношений исходного множества. (Операция проекции описана в разделе, посвященном реляционной алгебре). Обратимый пошаговый процесс замены данной совокупности отношений другой схемой с устранением избыточных функциональных зависимостей называется нормализацией.

Условие обратимости требует, чтобы декомпозиция сохраняла эквивалентность схем при замене одной схемы на другую, т.е. в результирующих отношениях:

* не должны появляться ранее отсутствовавшие кортежи;
* на отношениях новой схемы должно выполняться исходное множество функциональных зависимостей.


1NF - первая нормальная форма
Для обсуждения первой нормальной формы необходимо дать два определения:

Простой атрибут - атрибут, значения которого атомарны (неделимы).

Сложный атрибут - получается соединением нескольких атомарных атрибутов, которые могут быть определены на одном или разных доменах. (его также называют вектор или агрегат данных).

Теперь можно дать

Определение первой нормальной формы:

отношение находится в 1NF если значения всех его атрибутов атомарны.

Рассмотрим пример, заимствованный из статьи Е.Ф.Кодда:

В базе данных отдела кадров предприятия необходимо хранить сведения о служащих, которые можно попытаться представить в отношении
СЛУЖАЩИЙ(НОМЕР_СЛУЖАЩЕГО, ИМЯ, ДАТА_РОЖДЕНИЯ, ИСТОРИЯ_РАБОТЫ, ДЕТИ).

Из внимательного рассмотрения этого отношения следует, что атрибуты "история_работы" и "дети" являются сложными, более того, атрибут "история_работы" включает еще один сложный атрибут "история_зарплаты".
Данные агрегаты выглядят следующим образом:

# ИСТОРИЯ_РАБОТЫ (ДАТА_ПРИЕМА, НАЗВАНИЕ, ИСТОРИЯ_ЗАРПЛАТЫ),
# ИСТОРИЯ_ЗАРПЛАТЫ (ДАТА_НАЗНАЧЕНИЯ, ЗАРПЛАТА),
# ДЕТИ (ИМЯ_РЕБЕНКА, ГОД_РОЖДЕНИЯ).

Их связь представлена на рис. 1.
Написание статей

Рис.1 Исходное отношение.

Для приведения исходного отношения СЛУЖАЩИЙ к первой нормальной форме необходимо декомпозировать его на четыре отношения, так как это показано на следующем рисунке:
Написание статей

Рис.2. Нормализованное множество отношений.

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

Алгоритм нормализации описан Е.Ф.Коддом следующим образом:

* Начиная с отношения, находящегося на верху дерева (рис. 1.), берется его первичный ключ, и каждое непосредственно подчиненное отношение расширяется путем вставки домена или комбинации доменов этого первичного ключа.
* Первичный Ключ каждого расширенного таким образом отношения состоит из Первичного Ключа, который был у этого отношения до расширения и добавленного Первичного Ключа родительского отношения.
* После этого из родительского отношения вычеркиваются все непростые домены, удаляется верхний узел дерева, и эта же процедура повторяется для каждого из оставшихся поддеревьев.


2NF - вторая нормальная форма
Очень часто первичный ключ отношения включает несколько атрибутов (в таком случае его называют составным) - см., например, отношение ДЕТИ, показанное на рис. 2. При этом вводится понятие полной функциональной зависимости.

Определение:

неключевой атрибут функционально полно зависит от составного ключа если он функционально зависит от всего ключа в целом, но не находится в функциональной зависимости от какого-либо из входящих в него атрибутов.

Пример:

Пусть имеется отношение ПОСТАВКИ (N_ПОСТАВЩИКА, ТОВАР, ЦЕНА).
Поставщик может поставлять различные товары, а один и тот же товар может поставляться разными поставщиками. Тогда ключ отношения - "N_поставщика + товар". Пусть все поставщики поставляют товар по одной и той же цене. Тогда имеем следующие функциональные зависимости:

* N_поставщика, товар -> цена
* товар -> цена

Неполная функциональная зависимость атрибута "цена" от ключа приводит к следующей аномалии: при изменении цены товара необходим полный просмотр отношения для того, чтобы изменить все записи о его поставщиках. Данная аномалия является следствием того факта, что в одной структуре данных объединены два семантических факта. Следующее разложение дает отношения во 2НФ:

* ПОСТАВКИ (N_ПОСТАВЩИКА, ТОВАР)
* ЦЕНА_ТОВАРА (ТОВАР, ЦЕНА)

Таким образом, можно дать

Определение второй нормальной формы:

Отношение находится во 2НФ, если оно находится в 1НФ и каждый неключевой атрибут функционально полно зависит от ключа.


3NF - третья нормальная форма.
Перед обсуждением третьей нормальной формы необходимо ввести понятие транзитивной функциональной зависимости.

Определение:
Пусть X, Y, Z - три атрибута некоторого отношения. При этом X --> Y и Y --> Z, но обратное
соответствие отсутствует, т.е. Z -/-> Y и Y -/-> X. Тогда Z транзитивно зависит от X.

Пусть имеется отношение ХРАНЕНИЕ (ФИРМА, СКЛАД, ОБЪЕМ), которое содержит информацию о фирмах, получающих товары со складов, и объемах этих складов. Ключевой атрибут - "фирма". Если каждая фирма может получать товар только с одного склада, то в данном отношении имеются следующие функциональные зависимости:

* фирма -> склад
* склад -> объем

При этом возникают аномалии:

* если в данный момент ни одна фирма не получает товар со склада, то в базу данных нельзя ввести данные о его объеме (т.к. не определен ключевой атрибут)
* если объем склада изменяется, необходим просмотр всего отношения и изменение кортежей для всех фирм, связанных с данным складом.


Для устранения этих аномалий необходимо декомпозировать исходное отношение на два:

* ХРАНЕНИЕ (ФИРМА, СКЛАД)
* ОБЪЕМ_СКЛАДА (СКЛАД, ОБЪЕМ)

Определение третьей нормальной формы:
Отношение находится в 3НФ, если оно находится во 2НФ и каждый неключевой атрибут нетранзитивно зависит от первичного ключа.


BCNF - нормальная форма Бойса-Кодда
Эта нормальная форма вводит дополнительное ограничение по сравнению с 3НФ.

Определение нормальной формы Бойса-Кодда:

Отношение находится в BCNF, если оно находится во 3НФ и в ней отсутствуют зависимости атрибутов первичного ключа от неключевых атрибутов.

Ситуация, когда отношение будет находится в 3NF, но не в BCNF, возникает при условии, что отношение имеет два (или более) возможных ключа, которые являются составными и имеют общий атрибут. Заметим, что на практике такая ситуация встречается достаточно редко, для всех прочих отношений 3NF и BCNF эквивалентны.


Многозначные зависимости и четвертая нормальная форма (4NF)
Четвертая нормальная форма касается отношений, в которых имеются повторяющиеся наборы данных. Декомпозиция, основанная на функциональных зависимостях, не приводит к исключению такой избыточности. В этом случае используют декомпозицию, основанную на многозначных зависимостях.

Многозначная зависимость является обобщением функциональной зависимости и рассматривает соответствия между множествами значений атрибутов.

В качестве примера рассмотрим отношение ПРЕПОДАВАТЕЛЬ (ИМЯ, КУРС, УЧЕБНОЕ_ПОСОБИЕ), хранящее сведения о курсах, читаемых преодавателем, и написанных им учебниках. Пусть профессор N читает курсы "Теория упругости" и "Теория колебаний" и имеет соответствующие учебные пособия, а профессор K читает курс "Теория удара" и является автором учебников "Теория удара" и "Теоретическая механика". Тогда наше отношение будет иметь вид:

Написание статей


Это отношение имеет значительную избыточность и его использование приводит к возникновению аномалии обновления. Например, добавление информации о том, что профессор K будет также читать лекции по курсу "Теория упругости" приводит к необходимости добавить два кортежа (по одному для каждого написанного им учебника) вместо одного. Тем не менее, отношение ПРЕПОДАВАТЕЛЬ находится в NFBC (ключевой атрибут - ИМЯ).

Заметим, что указанные аномалии исчезают при замене отношения ПРЕПОДАВАТЕЛЬ его проекциями:

Написание статей


Аномалия обновления возникает в данном случае потому, что в отношении ПРЕПОДАВАТЕЛЬ имеются:

1. зависимость множества значений атрибута КУРС от множества значений атрибута ИМЯ
2. зависимость множества значений атрибута УЧЕБНОЕ_ПОСОБИЕ от множества значений атрибута ИМЯ.


Такие зависимости и называются многозначными и обозначаются как

ИМЯ ->> КУРС ИМЯ ->> УЧЕБНОЕ_ПОСОБИЕ

Нетрудно показать, что многозначные зависимости всегда образуют связанные пары, поэтому их часто обозначают

ИМЯ ->> КУРС | УЧЕБНОЕ_ПОСОБИЕ

Очевидно, что каждая функциональная зависимость является многозначной, но не каждая многозначная зависимость является функциональной.

Определение четвертой нормальной формы:

Отношение находится в 4NF если оно находится в BCNF и в нем отстутсвуют многозначные зависимости, не являющиеся функциональными зависимостями.


Зависимости по соединению и пятая нормальная форма (5NF)
До сих пор мы предполагали, что единственной операцией, необходимой для устранения избыточности в отношении, была декомпозиция его на две проекции. Однако, существуют отношения, для которых нельзя выполнить декомпозицию без потерь на две проекции, но которые можно подвергнуть декомпозиции без потерь на три (или более) проекций. Этот факт получил название зависимости по соединению, а такие отношения называют 3-декомпозируемые отношения (ясно, что любое отношение можно назвать "n-декомпозируемым", где n >= 2).

Детально этот вопрос здесь мы не обсуждаем (полное изложение см. в книге К.Дейта), заметим лишь, что зависимость по соединению является обощением многозначной зависимости. Отношения, в которых имеются зависимости по соединению, не являющиеся одновременно ни многозначными, ни функциональными, также характеризуются аномалиями обновления. Поэтому, вводится понятие пятой нормальной формы.

Определение пятой нормальной формы:

Отношение находится в 5НФ тогда и только тогда, когда любая зависимость по соединению в нем определяется только его возможными ключами.

Другими словами, каждая проекция такого отношения содержит не менее одного возможного ключа и не менее одного неключевого атрибута.
9
Елена
2439 / 788 / 24
Регистрация: 18.08.2009
Сообщений: 1,697
27.10.2010, 13:40 #11
Уважаемые форумчане, у меня есть предложение: среди вас есть грамотные ребята и девушки. Возможно у кого-то есть желание написать статью по какой-либо теме в акцессе, которую Вы хорошо разобрали и считаете, что в книгах нет такой подборки информации. Может попробуем в Акцессе собрать свой учебный материал?
5
ironegg
1898 / 775 / 31
Регистрация: 11.02.2010
Сообщений: 1,567
14.11.2010, 01:55 #12
если бы я, когда нибудь (ну вдруг?), написал свою статью, то я завел бы себе блог (на киберблогере?) и выложил ее там. а сюда ссылку. подходит?
1
Елена
2439 / 788 / 24
Регистрация: 18.08.2009
Сообщений: 1,697
14.11.2010, 18:14 #13
ironegg, я думаю да
0
all_angarsk
749 / 256 / 57
Регистрация: 13.12.2009
Сообщений: 982
11.02.2011, 04:06 #14
В качестве темы предлагаю
Работа с Access 2007, 2010 в windows 7, windows 2008 из офиса, ODBC и PHP
0
Елена
2439 / 788 / 24
Регистрация: 18.08.2009
Сообщений: 1,697
11.02.2011, 05:46 #15
all_angarsk, статью напишешь?
0
all_angarsk
749 / 256 / 57
Регистрация: 13.12.2009
Сообщений: 982
11.02.2011, 16:45 #16
если получится, все ограничено временем!!!!!!!
начало можно посмотреть
HTML5
1
http://www.cyberforum.ru/php-database/thread239338.html
только не много читателей
1
simply_sash
8 / 8 / 2
Регистрация: 23.08.2011
Сообщений: 14
23.08.2011, 15:23 #17
Статьи по MS Access пишу у себя в блоге. Если что-нибудь из моего творчества войдет в учебный материал -- буду только рад.
Могу порекомендовать статью о "резиновом" пользовательском интерфейсе -- при изменении размеров формы соответственно изменяются размеры и координаты элементов управления, расположенных в этой форме: http://csdeveloper.ru/izmenenie-razm...cess-2003.html
4
magirus
Почетный модератор
Эксперт по компьютерным сетямЭксперт Windows
27954 / 15674 / 959
Регистрация: 15.09.2009
Сообщений: 67,838
Записей в блоге: 78
04.12.2011, 09:51 #18
simply_sash, будут все благодарны, если Вы будете цитировать статьи здесь, хотя бы конкретные решения по задаваемым вопросам.
0
AlexSyr
62 / 15 / 1
Регистрация: 14.12.2010
Сообщений: 15
10.01.2012, 06:20 #19
Делал для себя когда-то "шпаргалку" по теме "Новый интерфейс MS Access 2007, 2010".
Может кому и пригодится.
Примечание:
- Работоспособность всех представленных примеров проверена в MS Access 2010 (32-бит);
- Ссылки, примеры запускаются напрямую из docx файла.
5
Вложения
Тип файла: rar Новый интерфейс MS Access 2007, 2010.rar (8.44 Мб, 865 просмотров)
Ameli
2059 / 1135 / 38
Регистрация: 05.11.2009
Сообщений: 1,604
01.02.2012, 08:12 #20
Хорошая база данных не получается случайно, ее структура должна тщательно прорабатываться. Плохо спроектированная база данных может стать накопителем избыточной информации, дублирования данных, источником множества ошибок, приводящим к неверным решениям.
Дублирование данных - главный враг правильной структуры базы данных, оно приводит к ненужной дополнительной работе и ошибкам при работе с бд. С таким же успехом все данные с повторами можно было бы хранить в одной таблице Excel-а. Вы же решили создать базу данных, поэтому разработка правильной ее структуры очень важна.
Основные понятия
База данных (бд) – упорядоченная совокупность данных, относящихся к определенной предметной области
Система управления базами данных (СУБД) - комплекс программных и языковых средств для создания и обработки баз данных
Реляционная модель данных:
•Данные в базе данных представляют собой набор отношений (relations), отсюда и название;
•Отношения (таблицы) отвечают определенным условиям целостности;
•Поддержка операторов манипулирования отношениями (реляционная алгебра, реляционное исчисление)
Кроме того в состав реляционной модели включают теорию нормализации.
Ms Access относится к реляционным СУБД.
Класс объектов (сущность) – совокупность объектов, обладающих одинаковым набором свойств.
Например, в базе данных о ВУЗе сущностями являются студенты, преподаватели, предметы.
Атрибут (свойство) – определенная часть информации о некотором объекте. Атрибуты – это поля (столбцы) таблиц. Например, для объекта Студент атрибутами будут Фамилия, Имя, Отчество.
Ключевой атрибут - это одно или несколько полей, комбинация значений которых однозначно определяет каждую запись в таблице
Связь (отношение) – способ, которым связана информация о разных объектах. Есть три типа отношений между таблицами:
•«один-к-одному» (1:1) – каждой записи в одной таблице соответствует одна запись в другой таблице. Встречается довольно редко, в основном, когда часть информации об объекте редко используется.
•«один-ко-многим» (1:М) – каждой записи в одной таблице соответствует несколько записей в связанной таблице. Наиболее распространенный тип связей.
Например, в бд должна храниться информация о студентах и результатах сдачи ими экзаменов (дата сдачи, предмет, оценка). Если все это хранить в одной таблице, то информация о студенте будет дублироваться по каждой сдаче им экзамена, поэтому объем таблицы неоправданно возрастет. Решение: создание двух таблиц Студенты и Экзамены. Для связи в таблице Экзамены можно использовать только часть информации о студенте, сдающем экзамен. Но она должна однозначно определять каждого студента, например, это может быть номер зачетки.
Итак, таблица Студенты должна иметь ключевое поле Номер зачетки, таблица Экзамены будет содержать следующие поля: Номер зачетки, предмет, дата, оценка, и будет связана с таблицей Студенты по полю Номер зачетки связью «один-ко-многим».
При этом поле Номер зачетки таблицы Студенты является первичным ключом, а таблицы Экзамены - внешним ключом (т.е. ссылкой на первичный ключ другой таблицы).
•«многие-ко-многим» (М:М) – множеству записей одной таблицы соответствуют множество записей в связанной таблице.
Эта связь не соответствует понятию нормальности таблиц и должна быть устранена путем замены двумя связями «один-ко-многим». Реализуется это с помощью введения третей дополнительной таблицы.
Например, Студенты изучают несколько Предметов - связь «многие-ко-многим». Для приведения к правильной структуре надо ввести дополнительную таблицу Изучение предметов, которая будет содержать ключевые поля обеих таблиц и будет связана с каждой из них связью «один-ко-многим».

Модель "сущность-связь" (ER-модель)
(англ. entity-relationship model, ERM) – концептуальная модель бд, которая отражает наиболее важные объекты предметной области и связи между ними. Моделирование основано на использовании графических диаграмм - ER-диаграмм (Entity-Relationship Diagrams), в результате получается наглядная концептуальная схема базы данных, понятная всем.
Основные этапы создания ER-диаграммы:
•Определение сущностей
•Определение связей
•Определение атрибутов
•Определение атрибутов, являющихся первичными ключами
•Создание диаграммы "сущность-связь"
На диаграмме сущность изображается в виде прямоугольника, содержащего его имя, выражаемое существительным. Связь изображается линией, которая связывает две сущности, участвующие в отношении. Тип связи обычно обозначают так: возле сущности со стороны «один» ставят 1, возле сущности со стороны «многие» - М или N, однако встречаются и другие обозначения, например, вилка (разветвление) возле сущности со стороны «многие». Необязательность связи обычно помечается незакрашенным кружочком на конце связи, иногда пунктирной линией. Название связи выражается глаголом в изъявительном наклонении настоящего времени «Имеет», «Принадлежит» т.д.; или глаголом с поясняющими словами: «Включает в себя» и т.д. и заключается в ромб. Атрибуты сущности иногда заключают в овалы и помещают на диаграмму возле каждой сущности, иногда помещают в прямоугольник сущности, иногда вообще не обозначают на диаграмме. Среди атрибутов выделяют ключевой.
В приложении примеры ER-диаграмм.
Пример 1: названия связей обозначены ромбами, типы связей - 1:N, атрибуты не обозначены
Пример 2: тип связи со стороны «многие» обозначен вилкой, атрибуты по каждой сущности внесены в прямоугольник, атрибуты, по которым осуществляется связь, подчеркнуты.
Пример 3: основные атрибуты обозначены в овалах, типы связей 1:N

Теория нормализации
Нормальная форма – совокупность требований, которым должно удовлетворять отношение в реляционной модели данных, чтобы избежать избыточности, которая может привести к логически ошибочным результатам выборки или изменения данных.
Проще говоря, это правила, которые позволяют сделать структуру бд эффективной и избежать трудностей в работе с ней в дальнейшем.
Процесс преобразования отношений бд к виду, отвечающему нормальным формам, называется нормализацией.
Т.е. это процесс усовершенствования структуры в соответствии с правилами нормализации - устранение избыточности и несогласованности данных, что сделает структуру бд более эффективной и надежной.
Существует 6 нормальных форм, т.е. 6 стадий совершенствования, однако на практике разработчики обычно пользуются первыми тремя.
Первая нормальная форма (1НФ):
•Все строки различны
•Все элементы внутри атомарны (неделимы), т.е. не списки
Пример таблицы Преподаватели, не находящейся в 1НФ:
ПреподавательПредмет
ИвановМат анализ, Векторный анализ
ПетровОбщий курс физики
В этой таблице в одной из ячеек содержится список из двух элементов: Мат анализ, Векторный анализ, т.е. не является атомарным. Исправить можно разбиением на две таблицы: Преподаватели и Чтение лекций преподавателями, связанных между собой связью «один-ко-многим»:
Код преподавателяФамилия преподавателя
1Иванов
2Петров
ПреподавательПредмет
1Мат анализ
1Векторный анализ
2Общий курс физики
Эти таблицы находятся в первой нормальной форме. Во второй таблице поле Преподаватель – числовой код таблицы Преподаватели.
Методы приведения к 1НФ:
•Устраните одинаковые строки в таблицах
•Создайте отдельную таблицу для каждого набора данных
•Идентифицируйте каждый набор связанных данных с помощью первичного ключа
Вторая нормальная форма (2НФ):
•отношение находится в 1НФ
•каждый неключевой атрибут функционально полно зависит от первичного ключа.
Второе правило можно понять на примере, когда первичный ключ состоит из нескольких полей. Т.е. каждую строку можно идентифицировать с помощью набора данных. Например, эта таблица находится в 1НФ, но не во 2НФ:
КурсПредметКол-о часовСтудент
1Мат анализ100Иванов
1Векторный анализ50Иванов
2Мат анализ120Петров
В этой таблице первичный ключ составляют два поля: курс и предмет, Кол-о часов функционально полно зависит от них обоих, т.к. определяется одновременно и курсом, и предметом. А вот студент зависит только от курса и не зависит от предмета, т.е. он функционально не полно зависит от всего ключа и функционально полно от его части. Исправляется разделением на две таблицы + введение третей Предметы:
КурсСтудент
1Иванов
2Петров
КодПредметаПредмет
1мат анализ
2векторный анализ
КурсПредметКол-о часов
11100
1250
21120
Теперь эти таблицы во 2НФ.
Методы приведения ко 2НФ:
•Создайте отдельные таблицы для наборов значений, относящихся к нескольким записям (что мы и сделали)
•Свяжите эти таблицы с помощью внешнего ключа (в нашем случае это поле Курс)
Третья нормальная форма (3НФ):
•Отношение находится во 2НФ
•Неключевые атрибуты не зависят между собой
Таблица Студенты находится во 2НФ, но не в 3НФ:
Номер зачеткиФамилияГруппаКуратор
1Иванов1Куратор1
2Петров1Куратор1
3Сидоров2Куратор2
Куратор зависит от студента, но он также зависит от группы (неключевого поля). Наличие этого поля в этой таблице приводит к дублированию куратора по каждому студенту одной группы, поэтому необходимо выделить таблицу Группы:
ГруппаКуратор
1Куратор1
2Куратор2
Номер зачеткиФамилияГруппа
1Иванов1
2Петров1
3Сидоров2
Метод приведения к 3НФ:
•Удалить поля, зависящие от неключевых элементов, выделить их в отдельную таблицу, связать с помощью внешнего ключа (Группа в нашем случае).
Нормальная форма Бойса-Кодда (НФБК):
•Отношение находится в 3НФ
•Первичный ключ не зависит от неключевых элементов
Например, таблица Экзамены находится в 3НФ, но не в НФБК:
Номер зачеткиНомер паспортаПредметОценка
1СВ1019Информатика5
2СВ1020Математика5
3СВ1056Физика4
Если ключевым сделать Номер зачетки, то все остальные поля будут зависеть только от него, но Номер зачетки соответствует Номеру паспорта, и наоборот. Решается введением еще одной таблицы Студенты:
Номер зачеткиНомер паспорта
1СВ1019
2СВ1020
3СВ1056
Номер зачеткиПредметОценка
1Информатика5
2Математика5
3Физика4
И использованием одного из них в качестве ключевого, а в таблице Экзамены - в качестве связующего с таблицей Студенты.
Четвертая нормальная форма (4НФ):
•Отношение находится в НФБК
•В нем отсутствуют многозначные зависимости
Например, таблица Преподаватель (Фамилия, Предмет, Учебное пособие), хранящая сведенья о предметах, читаемых преподавателем, и написанных им пособиях. Здесь видно значительную избыточность, и если понадобится добавить Иванову еще и предмет Теория удара, то придется добавлять еще и пособие, написанное им по этому предмету, которого может и не быть в природе. Тем не менее, таблица находится в НФБК (ключевое поле Фамилия).
ФамилияПредметУчебное пособие
ИвановТеория упругостиУчебное пособие1
ИвановТеория упругостиУчебное пособие2
ИвановТеория колебанийУчебное пособие3
ПетровТеория колебанийУчебное пособие4
Решается разбиением на две таблицы: Предметы по преподавателям, Учебные пособия по преподавателям:
ФамилияПредмет
ИвановТеория упругости
ИвановТеория колебаний
ПетровТеория колебаний
ФамилияУчебное пособие
ИвановУчебное пособие1
ИвановУчебное пособие2
ИвановУчебное пособие3
ПетровУчебное пособие4
Пятая нормальная форма (5НФ):
Отношение находится в 5НФ тогда и только тогда, когда любая зависимость по соединению в нем определяется только его возможными ключами.
Другими словами, каждая проекция такого отношения содержит не менее одного возможного ключа и не менее одного неключевого атрибута.

Основные этапы проектирования базы данных
1.Определить цель создания бд: задачи, способы использования, пользователи. Какие функции должна выполнять бд, на какие вопросы должна давать ответы, какие выходные данные вы хотите получить в итоге.
2.Собрать все данные, которые будут храниться в бд: запишите все, что должно храниться в бд
3.Распределить данные по таблицам: каждой группе данных – своя таблица. Например, для ВУЗа: Студенты, Предметы, Преподаватели, Экзамены и т.д.
Проанализируйте данные, встречаются ли повторы? Например, часто ли повторяются должности преподавателей? Найдите такие повторы и создайте для них отдельную таблицу.
4.Распределить элементы данных по столбцам: определить какие данные должны быть в каждой таблице, каждый элемент данных – столбец таблицы. Например, для таблицы Студенты это могут быть Номер зачетки, Фамилия, Имя, Отчество, Дата рождения и т.д. Здесь есть два основных правила:
-Не включайте вычисляемые данные в таблицу: их всегда можно получить в запросах, формах и отчетах, а в таблицах эта информация избыточна, кроме того может быть устаревшей.
-Разбивайте информацию на минимальные логические компоненты для удобства их дальнейшего извлечения. Например, ФИО лучше разбить на три поля.
Советы по именам полей:
-Давайте понятные, не слишком длинные имена полям
-Если имя поля состоит из нескольких слов, не разделяйте их пробелами. Это затрудняет обращение к ним в программном коде VBA или в выражениях (формулах). Соедините слова и начинайте каждое слово с большой буквы: НомерГруппы, или разделите их символом подчеркивания: Номер_группы.
Тоже относится и к именам таблиц.
На этом этапе также нужно определить типы данных полей, они позволяют позволяют обеспечить точность вводимых данных, а также повзоляют экономить дисковое пространство, поскольку определяют размеры полей.
5.Определить ключевые поля таблиц, т.е. ненулевые поля, однозначно определяющие каждую запись таблицы. Самый простой и надежный способ – введение поля-счетчика, который автоматически ставит номер записи. Кроме того счетчики удобно использовать для сортировки по мере ввода информации в таблицу, поэтому я советую всегда их использовать.
6.Создать связи между таблицами: вы разбили данные по таблицам, теперь необходимо выбрать способ, которым Access будет вновь объединять сведения таблиц.
Проанализируйте таблицы и определите, как данные одной таблицы связаны с данными другой таблицы. Возможно, будет необходимо добавить дополнительные поля или даже таблицы для создания необходимых связей.
Связи устанавливаются между первичным ключом одной таблицы и внешним ключом другой таблицы (т.е. ссылкой на первичный ключ первой таблицы). Значения в связанных полях при этом совпадают.
Как уже говорилось выше, используйте связи "один-ко-многим", если у вас получаются связи других типов, скорей всего структуру надо пересмотреть: "один-к-одному" - объединить в одну таблицу, "многие-ко-многим" - ввести дополнительную таблицу. Их использование целесообразно лишь в редких случаях.
В Microsoft Access обеспечивается возможность автоматической проверки целостности данных в связанных полях. Целостность даных означает систему правил, используемых для поддержания связей между записями в связанных таблицах, а также для обеспечения защиты от случайного удаления или изменения связанных данных. Установить проверку целостности можно, если:
-поле одной из таблиц является ключевым или имеет уникальный индекс
-связанные поля имеют один тип данных. Или одно из них счетчик, а второе числовое с Размером поля - Длинное целое.
Чтобы целостность обеспечивалась для определенной связи, при ее создании нужно установить флажок Обеспечение целостности данных.
7.Усовершенствовать структуру: проверьте структуру на наличие ошибок, заполните таблицы образцами данных, проанализируйте полученные результаты, примените правила нормализации, чтобы проверить правильность структуры. Внесите в таблицы все необходимые изменения.
Приведенные ниже вопросы помогут структурировать данные.
•Действительно ли в каждом поле хранится элементарная единица данных?
•Уникальна ли каждая запись, или они иногда повторяются?
•Не повторяются ли какие-то данные или группы данных в нескольких записях или таблицах?
•Можно ли легко изменить одну запись, не изменяя при этом другую?
•Действительно ли каждая из записей содержит все относящиеся к ней сведения?
•Действительно ли каждая из записей содержит только те сведения, которые относятся исключительно с ней?
•Есть ли поля, которые зависят от других полей в таблице?


Пример проектирования базы данных

Обсуждение статьи здесь
31
Миниатюры
Написание статей   Написание статей   Написание статей  

01.02.2012, 08:12
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
01.02.2012, 08:12

Объявляется тендер на написание простейшей БД!!
Объявляется тендер на написание простейшей БД! Кто заинтересовался пишите на...

Написание запроса к нескольким таблицам
Еще раз здравствуйте! Необходимо написать запрос который возвращает мне ФИО...

Написание сложного запроса SQL
Задача такая: Оператор телефонной связи берет абонентскую плату 300р. и абонент...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru