Переход от файловых систем к базам данных

Переход от файловых систем к базам данных

Электронные картотеки и системы файлов

Чтобы понять, почему классические электронные картотеки и различные формы систем, основанных на отдельных файлах, рано или поздно становятся неудобными и вынуждают переходить к централизованной базе данных, полезно мысленно перенестись в эпоху 50–60-х годов XX века, когда появлялись первые электронно-вычислительные машины (ЭВМ).

Тогда любой расчёт или учёт данных сводился к тому, что инженеры и математики писали специальные программы, а программисты «зашивали» логику работы с информацией непосредственно внутрь этих программ. Для хранения сведений (например, списков сотрудников, сводок о заказах, научных расчётов) чаще всего заводились отдельные файлы. Если возникала потребность в дополнительном поле (скажем, увеличить длину фамилии с 20 до 25 символов), программисту приходилось:

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

Такой подход со временем показал множество узких мест. Если разные отделы в одной организации создавали «свои» картотеки, неизбежно возникала избыточность данных: у одной машины или подразделения хранился некий старый файл (например, с устаревшим телефоном клиента), у другой — более новая версия. В итоге данные о контрагенте могли расползаться на несколько десятков копий, а их синхронизация превращалась в достаточно сложную и трудоемкую задачу.

Кроме того, файлы на разных машинах часто оказывались структурно несовместимы: где-то фамилия занимала 20 байт, а где-то 15; в одном отделе разработчики писали на одном языке программирования, а в другом — на другом, с совершенно иной системой записи данных. Чтобы собрать единый отчёт или агрегировать информацию «из нескольких мест», требовалось изобретать громоздкие способы синхронного чтения разных файлов, что становилось затруднительно и для программиста, и для самой машины.

Всё это можно назвать эволюционно понятным этапом — разработчики поначалу пытались “машинным” способом воспроизвести принцип бумажной картотеки: каждая запись в своей карточке, карточки лежат в ящиках, а чтобы найти информацию, нужно найти нужный «ящик». Но в условиях быстро растущих объёмов информации и числа пользователей такой подход начал явно буксовать. Именно тогда постепенно сформировалось убеждение, что для хранения больших массивов данных и многопользовательского доступа необходимо придумывать более гибкие и централизованные решения.

Даже сегодня существуют простые приложения или утилиты, которые работают с единственным файлом (или двумя-тремя) и не требуют полноценной СУБД. Однако как только растёт количество пользователей, появляется потребность в совместном редактировании, сложных отчётах и быстрой фильтрации — системы файлов перестают удовлетворять современные требования.

Что такое база данных и зачем она нужна

Когда объём данных стал слишком велик, а требования пользователей стали включать одновременный доступ, быстрый поиск и гибкую выборку, появился новый подход: база данных (БД). Согласно ГОСТ 34.321–96, под БД понимают совокупность взаимосвязанных данных, организованных по определённой схеме для совместного использования.

Однако, справедливым будет и более расширенное определение:

База данных (database) — это организованная совокупность совместно используемых логически связанных данных и их описаний (метаданных), относящаяся к определённой предметной области и предназначенная для удовлетворения информационных потребностей организации.

Обращаясь к сути, зачем нужна база данных:

  • Снижение избыточности и предотвращение конфликтов версий. Если раньше приходилось хранить телефон клиента в десятках файлов, то теперь в централизованной БД мы ведём его только в одном месте.
  • Совместный доступ. Разные пользователи могут не просто просматривать, но и одновременно обновлять сведения, не рискуя затереть изменения друг друга.
  • Централизованное управление. Существует единая «точка входа» — специальная программа (СУБД), которая следит, чтобы данные оставались непротиворечивыми, и выдаёт доступ только тем, кто имеет на это право.
  • Надёжность и безопасность. Благодаря механизмам резервного копирования и контроля транзакций (в более поздних моделях) база данных сможет восстанавливаться после сбоев и защищать сведения от несанкционированных действий.

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

Эволюция моделей БД

Переход к базе данных не сразу дал идеальную концепцию хранения. В 50-х и 60-х годах появились первые промышленные ЭВМ, вычислительные мощности начали расти, а вместе с ними рос и спрос на способы организации больших объёмов данных. Можно сказать, что «спусковым крючком» к массовому развитию БД послужили грандиозные технические проекты (например, космическая программа Apollo в США), где требовалось в реальном времени обрабатывать горы информации: от расчёта траектории полёта до хранения детализации заказов, выставляемых подрядчикам.

Стандартов и согласованного понимания, как именно строить базы данных, поначалу не было, поэтому появлялись разные модели БД:

Иерархическая модель

В данной модели данные представляются в виде перевёрнутого дерева: в корне (самом верхнем уровне) лежит «главный» объект, а от него отходят ветви к подчинённым объектам, у которых, в свою очередь, могут быть свои «потомки». Это было проще, чем хаотичные файлы, поскольку достаточно очевидно — один родитель, много потомков. Так было организовано, например, хранение структур «компания → отделы → сотрудники». Однако модель слишком жёстко требовала, чтобы у каждого дочернего узла был только один родитель. Если реальная жизнь требовала иначе (связи «многие ко многим»), в иерархической структуре это становилось затруднительным.

Сетевая модель

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

Реляционная модель

Принципиальный прорыв произошёл в 70-х, когда Эдгар Кодд предложил описывать данные в виде таблиц (отношений), связанных между собой с помощью общих полей (ключей). Математическая база реляционной модели (теория множеств, логика) позволила формализовать многие вопросы работы с данными. Реляционные СУБД приняли во внимание опыт предыдущих подходов и свели взаимодействие к понятным операциям: добавить запись, убрать, изменить, выбрать по условию. Были разработаны первые версии языка SQL (SEQUEL), позволяющие довольно просто «запрашивать» данные. Со временем реляционные СУБД, такие как IBM DB2, Oracle, MySQL и другие, заняли доминирующую позицию в мире.

Объектно-ориентированная модель

Когда в середине 80-х объектно-ориентированное программирование стало основой софта, стали появляться идеи хранить данные в виде объектов с методами, атрибутами и наследованием. Однако «чистые» объектные БД оказались слишком сложны в стандартизации. Наиболее удачные решения — это объектно-реляционные СУБД, где к реляционной основе добавлены механизмы, напоминающие объекты.

Слабо структурированные и документ-ориентированные БД (NoSQL)

С появлением больших интернет-проектов и сменой характера данных (часто меняющиеся, не всегда фиксированной структуры) стали набирать популярность документо-ориентированные и другие нереляционные БД, способные хранить информацию, к примеру, в формате JSON. Они отлично справляются со сколь угодно «разношерстными» документами, поддерживают горизонтальное масштабирование и высокую скорость вставки. Однако для традиционных корпоративных задач зачастую всё-таки используется классическая реляционная модель, поскольку она обладает более жёсткими и отработанными механизмами целостности.

Эволюция в БД
Эволюция БД

Тот факт, что реляционные базы уже несколько десятилетий занимают лидирующие позиции, не отменяет существования и развития других моделей. Потребности современного мира (социальные сети, Big Data, аналитические хранилища) расширили область применения NoSQL и гибридных СУБД, но классически в первую очередь изучаются реляционные парадигмы.

Практическое задание

Представим, что вы стажёр в небольшом интернет-магазине. Вам отдали две “выгрузки” из разных отделов:

  • Klienty.txt — “справочник клиентов”
  • Zakazy.txt — “журнал заказов”

Но реальные данные редко бывают “идеальными”, поэтому в наборе данных у нас есть 6 “следов работы реальной организации” — небольших, но очень показательных:

  1. “Висячие заказы”: в Zakazy.txt есть несколько строк с ID_Клиента, которого нет в Klienty.txt (например, 121/130/999). Плюс есть одна строка, где ID_Клиента записан как 09 (это тот же 9, если привести поле к числу).
  2. “Двойники клиента”: один и тот же email и/или телефон встречается у разных ID_Клиента.
  3. Грязь в справочниках: один и тот же город написан по-разному (“Санкт-Петербург” vs “СПб”), встречаются лишние пробелы и варианты вроде “Санкт Петербург”, “С.-Петербург”.
  4. “Битые типы”: несколько дат записаны не в ISO-формате (YYYY-MM-DD), сумма может оказаться текстом (12 000), встречается отрицательная сумма, а в одном заказе отсутствует Дата_Доставки.
  5. Несогласованные справочники значений: единично встречаются значения “Способ_Оплаты” и “Способ_Доставки”, которых нет в оговорённом списке.
  6. Ограничение доступа по ролям: договоримся, что “оператору” нельзя видеть, например, адрес, а “аналитику” нельзя менять статусы.

Требование: Сделайте выводы и о проделанной работе в формате мини-отчета.

Исходные данные

  1. Файл «Klienty.txt»

Каждая строка содержит 8 полей, разделённых точкой с запятой (;).

Формат строки: ID_Клиента;ФИО;Телефон;Город;Адрес;Email;Дата_Регистрации;Статус

Поля:

  • ID_Клиента: уникальный числовой идентификатор (1..120).
  • ФИО: фамилия, имя и отчество.
  • Телефон: чаще всего в условном формате +7-9xx-xxx-xx-xx, но есть 1 строка “не по шаблону”.
  • Город: несколько крупных городов (повторяются), есть варианты написания и лишние пробелы.
  • Адрес: абстрактная уличная запись.
  • Email: в основном корректный email, но есть 1 некорректное значение и 1 пустое.
  • Дата_Регистрации: в интервале примерно от 2024-05 до 2024-12, но есть 1–2 строки с другим форматом даты.
  • Статус: «Обычный», «VIP» или «Заблокирован» (иногда с лишними пробелами).

Пример данных:

1;Соколов Иван Антонович;+7-996-132-13-21;Екатеринбург;ул. Сибирская, д. 95, кв. 190;sokolov.ivan1@mail.ru;2024-12-15;Обычный
2;Степанов Павел Глебович;+7-994-928-10-30;Москва;ул. Дружбы, д. 84;stepanov.pavel2@mail.ru;2024-08-16;Обычный
3;Смирнова Анастасия Антоновна;+7-959-370-15-68;Санкт Петербург;ул. Технологов, д. 44, кв. 98;smirnova.anastasiya3@mail.ru;2024-05-25;Обычный
...

Полный файл доступен по ссылке.

  1. Файл «Zakazy.txt»

Каждая строка содержит 7 полей, разделённых точкой с запятой (;).

Формат строки: ID_Заказа;ID_Клиента;Дата;Сумма;Способ_Оплаты;Способ_Доставки;Дата_Доставки

Поля:

  • ID_Заказа: уникальный номер заказа (1..150).
  • ID_Клиента: номер клиента (в основном 1..120, но есть “висячие” значения).
  • Дата: дата оформления (в 2025 году), в основном ISO YYYY-MM-DD, но есть 1–2 строки с другим форматом.
  • Сумма: целое число (примерно 300..25000), но есть выбросы: сумма текстом (12 000) и отрицательная сумма.
  • Способ_Оплаты: чаще всего «Наличные», «Карта», «Онлайн», но есть 1 значение вне списка.
  • Способ_Доставки: чаще всего «Курьер» или «Самовывоз», но есть 1 значение вне списка.
  • Дата_Доставки: обычно на 1–7 дней позже даты оформления, но есть 1 пустая дата и 1–2 выброса по срокам.

Пример данных:

1;1;2025-01-20;18283;Онлайн;Самовывоз;2025-01-21
2;31;2025-02-08;4292;Наличные;Курьер;2025-02-12
3;80;2025-02-28;2358;Наличные;Самовывоз;2025-03-05
...

Полный файл доступен по ссылке.

Задачи:

В процессе выполнения можете сверяться с контрольными подсказками:

  • Klienty.txt: 120 строк, ID_Клиента 1..120.
  • Zakazy.txt: 150 строк, ID_Заказа 1..150, max(Дата) (после приведения типов) = 2025-03-31.
  • В Klienty.txt: 2 “нестандартные” даты, 2 города с лишними пробелами, 1 пустой email, 1 некорректный email, 1 телефон “не по шаблону”, 1 группа дублей по email и 1 группа дублей по телефону.
  • В Zakazy.txt: 2 “нестандартные” даты, 1 сумма текстом (12 000), 1 отрицательная сумма (-500), 1 “оплата вне списка”, 1 “доставка вне списка”, 1 пустая Дата_Доставки, 1 заказ с Дата_Доставки раньше Дата.

1. “Это данные или просто текст, удачно разложенный по колонкам?”

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

Импортируйте Klienty и Zakazy в Excel так, чтобы это стали две нормальные таблицы (с заголовками), приведите типы (ID — число, даты — дата, сумма — число) и соберите короткий список “подозрительных” строк, где тип не распознался/сломался (например, дата как текст или пустая дата). Результат — лист DataQuality с найденными проблемными строками + краткая заметка что именно было не так.

В Excel вам помогут:

  • Text Import Wizard при импорте TXT/CSV (можно сразу указать разделитель ; и типы столбцов).
  • “Базовые” преобразования: DATEVALUE(), VALUE(), IFERROR().
  • Для будущей корректности можно ограничить ввод дат/чисел/списков допустимых значений.

Почему в СУБД тип поля — это часть схемы, и что система выигрывает, заставляя вас определить типы заранее?

2. “Покажите заказ… но чтобы сразу было видно: кто это, откуда, и какой у него статус”

В этот момент сотрудники обычно делает первый “файловый грех”: склеивает всё в одну таблицу, потому что “так удобнее смотреть”. А через пару минут приходит второе требование: “а теперь обновите email клиента”. И вы внезапно понимаете, что email теперь живёт в трёх местах, а правду вы потеряли где-то по дороге.

Соберите “единый вид заказа” (как будто это один отчёт), где в каждой строке заказа есть: ID_Заказа, Дата, Сумма, Способ_Оплаты, Способ_Доставки, Дата_Доставки + из клиентов ФИО, Город, Email, Статус. Результат — лист UnifiedView, который обновляется при изменении исходных таблиц.

В Excel вам помогут:

  • XLOOKUP для подтягивания полей по ID_Клиента
  • IFNA/IFERROR + обработка #N/A как индикатора проблем (не найден клиент / “висячая” ссылка)

Почему JOIN лучше “склейки” с точки зрения актуальности данных?

3. “Бизнес не читает строки. Бизнес хочет ответы: найти, отфильтровать, посчитать”

Дальше начинается самое знакомое: “покажите крупные заказы за период”, “только VIP”, “какие доставки опоздали”, “выручка по городам”, “средний чек по статусам”. И вот тут видно, что “таблица” — это только начало. Нужен язык вопросов к данным: фильтры, условия, группировки, суммы/средние.

На основе UnifiedView (или связки двух таблиц) подготовьте три результата на листе Report:

  1. выборка “крупные заказы”: Сумма > 10000 за последние 5 дней данных (то есть от max(Дата) минус 4 дня), вывести Дата, Сумма, ФИО; Подсказка для самопроверки: после приведения типов max(Дата) должно получиться 2025-03-31 (значит “последние 5 дней” это 2025-03-27..2025-03-31).
  2. выборка “VIP и деньги”: Статус = VIP и Способ_Оплаты ∈ {Онлайн, Карта};
  3. отчёт “сколько и на сколько”: выручка и количество заказов по городу и по статусу (можно двумя сводными/двумя блоками).

В Excel вам помогут:

  • PivotTable для COUNT/SUM/AVG по городу/статусу/датам.
  • SUMIFS / COUNTIFS / AVERAGEIFS для отчётов “по условиям”.

Почему правильные типы критичны для агрегатов?

4. “А что если у нас не один ‘Иванов’, а два — и оба вроде как настоящие?”

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

Найдите “двойников” среди клиентов минимум по двум критериям: одинаковый email и/или одинаковый телефон у разных ID_Клиента. Результат — лист Duplicates со списком подозрительных пар/групп и коротким выводом, чем это опасно для отчётов (например, “один человек считается двумя клиентами”). Если в данных есть вариативность города (“СПб” vs “Санкт-Петербург”), покажите, как она искажает группировки (до/после нормализации).

Подсказка: в исходных данных есть как минимум 1 группа дублей по email и 1 группа дублей по телефону. Чтобы уложиться по времени: нормализацию города достаточно показать на одном примере (“СПб/Санкт-Петербург”), без приведения к единому виду всех городов.

В Excel вам помогут:

  • Conditional Formatting → Duplicate Values чтобы подсветить двойников.
  • Data → Remove Duplicates.
  • Advanced Filter → Unique records only (для выделения уникальных).
  • Для нормализации “СПб/Санкт-Петербург/лишние пробелы” — TRIM() + Find/Replace.

5. А что если у нас появятся “висячие данные”?

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

По логике вещей такие строки, которые их упоминают, должны исчезать, иначе возникает нарушение ссылочной целостности. Поэтому проверьте выданный выбор данных и убедитесь, точно ли там нет таких “хвостов”?

Найдите все заказы, у которых ID_Клиента не находится в таблице клиентов, и посчитайте, сколько таких заказов (и на какую сумму). Результат — лист Orphans со списком этих заказов + итоги (кол-во/сумма).

Подсказка: если ID_Клиента приведён к числу, то значение 09 должно совпасть с клиентом 9 и не считаться “висячим”. Самопроверка: при корректно приведённом ID_Клиента должно получиться 8 “висячих” заказов на сумму 92779.

В Excel вам помогут: XLOOKUP и обрабатывать #N/A записи.

Встречались ли вы с этим в Access, когда включали обеспечение целостности связи?

6. “А теперь представьте, что структура меняется. Маркетинг попросил новое поле” (опц.)

Сегодня вам достаточно Email. Завтра скажут: “добавьте Канал_привлечения”. Послезавтра: “у клиента может быть два email”. В файловом мире это выглядит как “переделаем табличку”. А в реальности — ломаются отчёты, ломаются склейки, ломаются инструкции, ломается всё, что держалось на прежней форме данных.

Дополнительно (по желанию), добавьте в клиентов новое поле (например, Канал_привлечения) и заполните его хотя бы для 10 строк, а затем проверьте, что ваш UnifiedView и Report продолжают работать.

Если после добавления столбца что-то “поехало” (частый случай при VLOOKUP с номером столбца), зафиксируйте где именно сломалось и что пришлось поменять. Если ничего не сломалось (часто бывает при XLOOKUP), тоже напишите почему. Результат — короткий вывод на листе Notes: “что изменили”, “сломалось/не сломалось”, “почему”.

В Excel вам помогут: перевести диапазоны в Excel Table и строить формулы на structured references

7. “Нас много. И иногда всё идёт не по плану: конфликты, перетирания, ‘а у меня было иначе’” (опц.)

Один оператор меняет email, второй меняет статус. Один успел сохранить, второй сохранил позже — и “кто-то потерял правку”. В файлах это часто выглядит как бытовая трагедия: “перезалей мне актуальную версию”. В СУБД это штатный режим: конкуренция изменений решается механизмами блокировок/транзакций, а не договорённостями.

Если осталось время, попробуйте воспроизвести “конфликт редактирования” и коротко описать, что произошло.

Если Access недоступен, достаточно в 3–5 предложениях описать сценарий “потерянного обновления” и какой механизм (блокировка/изоляция/транзакционность) вы ожидаете от СУБД.

Инструменты (Access): RecordLocks / режимы блокировки записей

Если файл базы повредился — в Access есть Compact & Repair

почему многопользовательская работа — базовая функция БД? Почему “просто держать файл” быстро перестаёт быть вариантом?

8. “Кому вообще можно видеть и менять данные?” (опц.)

Пока у вас файлы — у всех обычно есть всё. Но в реальной организации это заканчивается плохо: кому-то нельзя видеть адрес, кому-то нельзя менять суммы, кому-то нельзя трогать статусы. И тут очень быстро выясняется: “скрыть столбик” — это не безопасность, это просьба быть хорошими.

В .accdb нет полноценной user-level security как в старых .mdb, “по-взрослому” права доступа раскрываются в серверных СУБД.

Дополнительно: составьте на листе Notes “матрицу доступа” (роль → какие поля можно смотреть/менять). Например: “оператор” видит ФИО/город/статус и меняет статус, но не видит адрес; “аналитик” видит агрегаты и отчёты, но не меняет статусы/суммы.

И снова … Access

Импорт данных

  1. Откройте Access → Blank Database → создайте shop.accdb.
  2. External Data → New Data Source → From File → Text File и импортируйте Klienty.txt (Delimited, разделитель ;) в таблицу Clients. Аналогично импортируйте Zakazy.txt в таблицу Orders.

Если группа совсем “нулевая” в импорте TXT, можно упростить: сначала открыть TXT в Excel, сохранить как XLSX и импортировать из Excel. Но TXT-импорт тоже штатный.

Приведение типов и ключи (самое важное для новичков)

  1. Откройте ClientsDesign View:

    • ID_Клиента сделайте числовым (Long Integer) и назначьте Primary Key.
  2. Откройте OrdersDesign View:

    • ID_ЗаказаPrimary Key,
    • ID_Клиента → Long Integer,
    • Дата, Дата_Доставки → Date/Time,
    • Сумма → Number/Currency.

Без совпадения типов Clients.ID_Клиента и Orders.ID_Клиента Access не сможет нормально включить целостность связи.

Связь таблиц и целостность

  1. Database Tools → Relationships.
  2. Добавьте Clients и Orders.
  3. Перетащите Clients.ID_Клиента на Orders.ID_Клиента.
  4. Включите Enforce Referential Integrity (и по желанию каскадные опции).

Если целостность не включается с первого раза, это нормально: в наших данных есть “висячие заказы”, и Access заставит вас сначала их найти/исправить (или осознанно оставить связь без enforcement и зафиксировать это в Notes).

Запросы вместо “склейки”

  1. Create → Query Design → добавьте Clients и Orders.
  2. Выберите поля как в UnifiedView (из обеих таблиц) — это ваш аналог JOIN-отчёта.

“Найти и посчитать” по-СУБДшному

  1. Для выборок задавайте условия в строке Criteria (например, сумма > 10000, VIP, период дат).
  2. Для группировок включайте кнопку Totals (Σ) и используйте SUM/COUNT/AVG.

“Висячие” и “двойники”

  • “Висячие”: запрос с LEFT JOIN и условием, что со стороны клиентов поле пустое (Is Null) — это стандартный паттерн поиска orphan-records.
  • “Двойники”: запрос с группировкой по Email/Телефону и условием COUNT > 1.

Конфликт редактирования и восстановление

  • Для ощущения многопользовательского режима попробуйте открыть базу с двух экземпляров Access и править одну запись; поведение регулируется RecordLocks.