База данных поликлиники (больницы) в формате MySQL. Версия: 8.0.28 В архиве модель для MySQL Workbench и готовый скрипт базы данных, который можно импортировать или просто выполнить в MySQL Workbench для создания физической базы данных на компьютере.
База данных поликлиники
База данных поликлиники является довольно популярным запросом в рунете. В этой статье я рассмотрю вопрос проектирования базы данных и физической разработки. То есть, первая часть статьи будет освещать разработку модели базы данных, а вторая часть статьи будет описывать создание базы данных поликлиники из нашей разработанной модели.
И в самом конце статьи вы сможете скачать готовую базу данных поликлиники, которую мы с вами получим.
Проектирование базы данных поликлиники
Проектирование базы данных — это очень большая область, включающая в себя множество схем, представленных в том числе и на языке описания UML, а также включающих в себя описание бизнес-процессов в различных нотациях, например, в нотации idef0.
Здесь я не буду разрабатывать эти схемы. Я, по большому счету, проектировал данную базу данных просто на обычном листе бумаги, постоянно что то вычеркивал, менял таблицы, поля, связи …
В общем, я в этой статье ограничусь только основными схемами, которые вам покажут объекты и связи между ними в разрабатываемой базе данных.
Предметная область «Поликлиника»
Перед разработкой базы данных, следует изучить предметную область, для которой будет вообще вестись, собственно, вся разработка. Опять таки, замечу, что для этих целей принято использовать нотации вроде idef0, ведь она дает возможность схематически изобразить весь бизнес-процесс интересующей нас предметной области.
Но я поступлю несколько иначе, чтобы не делать из статьи книгу. Я опишу словесно, а в качестве иллюстрации приложу мнемо-схему.
Что представляет собой типичная поликлиника? Прежде всего, в каждой поликлиники есть такой отдел как регистратура, где у нас хранятся все карточки наших пациентов. В поликлинике также есть корпуса, отделения. В каждом отделении имеются кабинеты, в которых врачи осуществляют прием больных граждан. Это типичная картина поликлиники.
В последнее же время в поликлиниках нашей страны осуществляются продажи лекарственных препаратов. Я бы сказал, что это очень удобно и это можно учесть в нашей с вами разрабатываемой базе данных.
Также в поликлиниках оказываются и платные услуги. В настоящее время уже не столь важно, к какому типу принадлежит поликлиника. Это может быть как коммерческая организация, так и государственная. В коммерческой практически все оказываемые услуги являются платными, а в государственной поликлинике также есть бесплатные услуги и есть услуги, которые не входят в обязательный пакет бесплатного медицинского обслуживания.
Аптека поликлиники может выступать в роли самостоятельной организации, которая просто берет в аренду одно из помещений поликлиники, а может выступать как отдел поликлиники. Почему бы и нет? Если поликлиника коммерческая, то это вполне может быть ее вспомогательным видом деятельности.
И я считаю, что этот момент тоже стоит учесть в нашей базе данных, а не ограничиваться только лишь разработкой базы данных для регистратуры поликлиники. Так наша база данных будет намного интересней и функциональней.
Еще стоит отметить, что все эти лекарственные препараты где то должны храниться. Следовательно, у поликлиники должно быть складское помещение.
Не стоит забывать и о том, что доступ к базе данных обычно осуществляется разными специалистами, следовательно потребуется вести учет пользователей, сотрудников, должностей.
Вообще, образно говоря, для того, чтобы спроектировать базу данных, следует определить функции программы, которую планируется разработать. И исходя уже из этих функциональных требований к разрабатываемому программному обеспечению разрабатывается база данных. Ну то есть, она разрабатывается под что-то конкретное.
Поэтому, давайте с вами сейчас определим что мы хотим от нашей будущей программы, чтобы потом сделать проект базы данных.
Функциональные требования к ИС «Поликлиника»
Функциональные требования к ИС «Поликлиника» (назовем ее так):
- учет корпусов поликлиники;
- учет отделений в разрезе корпусов и кабинетов в каждом отделении;
- учет должностей по группам;
- учет сотрудников поликлиники, пользователей и их контактных данных;
- организация возможности авторизации пользователей в системе;
- учет карт пациентов в регистратуре поликлиники (база данных пациентов поликлиники);
- организация возможности записи на прием к врачу;
- формирование истории болезни пациентов;
- учет анализов, сданных пациентами и результатов этих анализов;
- учет лекарственных препаратов;
- учет производителей лекарственных препаратов;
- учет поставщиков лекарств;
- формирование заявок поставщикам на лекарственные препараты с возможностью отправки заявок на электронную почту поставщика;
- учет поступлений товаров от поставщиков;
- возможность ведения учета брака, просроченных лекарственных препаратов;
- организация механизма возврата некачественного товара (лекарственных препаратов) поставщикам;
- организация продаж лекарственных препаратов в аптеке поликлиники;
- учет оказываемых услуг поликлиникой.
Таким образом, функциональные требования к информационной системе довольно обширны, а это значит, что нам потребуется выполнить проектирование базы данных с большим числом объектов.
Мнемосхема «TO BE» (Как должно быть)
Давайте рассмотрим мнемосхему деятельности поликлиники с использованием нашей будущей информационной системы.
Опишем нашу с вами мнемосхему работы поликлиники и после этого мы сможем перейти к построению информационной модели данных поликлиники.
Начинается у нас все с пациента. Пациент обращается в регистратуру поликлиники непосредственно или через сайт (если планируется разработать веб-приложение). Работник регистратуры проверяет наличие в картотеке клиники медицинской карты пациента. Если такой карты нет, то заводит новую карту на обратившегося пациента. Следует заметить, что речь идет не об обычной бумажной карте, а об электронной карте пациента, хранящейся в базе данных информационной системы.
Далее пациент выбирает нужного ему доктора и записывается на свободное время. Записать клиента также может и работник регистратуры. Это будет удобно, если, например, в качестве пациента будет выступать пожилой человек, который не умеет пользоваться современными технологиями.
После записи, работник регистратуры выдает пациенту талон, в котором указаны кабинет, ФИО доктора, дата и время записи на прием. Карта пациента при этом «уходит» из регистратуры к этому доктору, а не отдается на руки пациенту, как при классическом подходе.
В назначенное время пациент приходит к доктору, показывает талон, доктор, используя данные талона, понимает, что к нему пришел пациент (условно Иванов) и среди своих электронных карт в программе находит карту Иванова.
Доктор выслушивает жалобу пациента, записывает ее в карточку пациента в информационную систему и, если нужно назначает ему сдачу анализов, выдавая пациенту талон с названиями необходимых для прохождения анализов. Сам же доктор создает запись в информационной системе о том, какие анализы должны быть сданы пациентом. Эту запись увидит у себя в личном кабинете лаборант. При этом доктор может записать пациента на повторный прием.
Далее пациент идет с талоном к лаборанту, где он сдает необходимые анализы. Лаборант вносит результаты этих анализов в созданную доктором запись.
На повторном приеме у доктора, последний в соответствии с анализами устанавливает заболевание (диагноз) и назначает курс лечения, фиксируя все это в электронной карте пациента. Причем доктор может установить диагноз сразу, не назначая сдачу анализов.
После выздоровления пациента, доктор на последнем приеме создает квитанцию на оплату услуг поликлиники, которую он распечатывает и отдает пациенту, а карту возвращает в регистратуру. Физически карта пациента никуда не переходит и не высылается ни по каким-либо каналам связи, а все время остается в базе данных. Просто у нее меняется статус местонахождения. Своеобразный маячок. Получается такая вот электронная регистратура поликлиники.
Созданная доктором квитанция становится видна кассиру как запись в информационной системе. Далее пациент направляется с бумажной версией квитанции в кассу клиники и показывает ее кассиру, по которой кассир определяет, какую из электронных квитанций следует закрыть. Пациент оплачивает предоставленные услуги. При этом кассир, вносит оплату в базу данных и печатает кассовый чек.
Здесь следует отметить, что когда доктор назначает лечение, он обычно выписывает необходимые пациенту лекарственные препараты. Так вот все это пациент может приобрести в клинике в той самой упомянутой выше аптеки. Пациент также может подойти с этим рецептом, выписанным доктором к фармацевту (кассиру аптеки) и приобрести лекарства.
Отдельно стоит сказать о том, что в эту схему можно грамотно внедрить механизм работы склада, ведь лекарственные препараты должны обязательно храниться на складе аптеки поликлиники. Собственно механизм работы такой схемы будет мало чем отличаться от работы типичной аптеки. Но внедрить это в работу поликлиники будет достаточно интересно, чтобы функционал программы был более обширным. А почему бы и нет?
Для этого нам понадобится менеджер склада, который будет взаимодействовать с поставщиками. Менеджер склада формирует заявку на товары и направляет ее поставщику. Поставщик в сопровождении товарной накладной (ТОРГ-12) поставляет товары на склад аптеки поликлиники. Стоит отметить, что товары склада могут использоваться не только в аптеке, но и в стационаре поликлиники. Поэтому, я считаю, что такое комплексное внедрение очень удобно.
После проверки товаров, менеджер подписывает второй экземпляр накладной и отдает отправляет ее поставщику. Прием товара при этом фиксируется в программе.
Если при поступлении товара выявлен брак, просроченные товары или просто товары не соответствуют накладной, то составляется акт, формируется накладная на возврат и эти сведения заносятся в информационную систему.
Бракованный же товар направляется обратно поставщику вместе с подписанным актом и накладной на возврат товара. Поставщик же обратно присылает подписанный экземпляр накладной и акта. Операции пересылки можно организовать, например с использованием систем документооборота (по согласованию с поставщиками).
Также менеджер у нас формирует из программы отчет о поступлении, об остатках товаров на складе, а также можно разработать еще ряд необходимых отчетов.
В этой схеме не отображены такие роли как главный врач, заместитель главного врача и так далее. Но их можно использовать также. Можно даже добавить экономиста, который будет определять спрос на услуги, спрос на аптечные товары и тому подобное. Тут уже все будет ограничиваться потребностями клиники. Давайте же теперь перейдем непосредственно к формированию информационно-логической модели данных.
Информационно-логическая модель данных поликлиники
Логическая модель данных не зависит ни от какой-либо СУБД и создается сама по себе. Ее можно разработать как на бумаге, так и с использованием ряда компьютерных программ, таких как MS Visio.
Таких программ очень много. По сути, здесь подойдет вообще любой из графических редакторов (предпочтительно конечно векторный). Мне нравится все свои схемы выполнять в CorelDraw. Если кто-то любит Adobe Illustrator — можете взять его.
Конечно существует еще очень много программ, предназначенных непосредственно для этой цели. Некоторые из низ позволяют затем экспортировать логическую модель в физическую уже для выбранной СУБД. На рисунке ниже изображена логическая модель данных поликлиники.
Здесь сразу стоит пояснить, что данная схема данных больницы является универсальной. То есть, ее можно использовать как в платной поликлинике, так и в бесплатной. Вы можете всем имеющимся услугам установить нулевую стоимость, если у вас бесплатная поликлиника, вы можете установить стоимость для конкретных услуг и только. Приведем описание схемы данных поликлиники.
Информационно-логическая модель данных поликлиники (больницы) состоит из 50 сущностей. Сущности связаны между собой отношением один-ко-многим, таким образом, чтобы удовлетворять принципам нормализации базы данных. Схема данных имеет как справочные, так и оперативные объекты. Давайте перейдем ближе к описанию.
Поликлиника обычно представляет собой один или несколько корпусов (может быть даже расположенных на разных улицах и кварталах), отделений внутри корпусов (иногда отделение может занимать целый корпус) и кабинетов внутри каждого из таких отделений.
Поэтому в нашей схеме обязательно присутствуют три объекта: корпуса, отделения и кабинеты.
Поскольку в каждом корпусе у нас может быть от одного до нескольких отделений, то объект «Отделения» является дочерним объектом по отношению к объекту «Корпуса».
Аналогично, в каждом отделении имеется несколько кабинетов, поэтому объект «Кабинеты» является дочерним, то есть подчиненным объектом, по отношению к объекту «Корпуса».
По сути — эти объекты являются справочниками, но с подчинением друг другу, как указано в абзаце выше.
В поликлинике, как и в любой другой организации, имеются должности, которые удобно разделить на группы. С этой целью в схеме данных имеется родительский объект «Группы должностей» и дочерний (подчиненный) — «Должности».
В информационной системе всегда имеются пользователи. Такие пользователи должны где-то учитываться. С этой целью в имеющейся схеме предусмотрен справочный объект «Пользователи».
У каждого из пользователей может быть от одного до нескольких телефонных номеров, поэтому их удобно вынести в отдельный подчиненный объект «Телефоны».
Теперь более интересная вещь. Каждый пользователь занимает определенную должность и связывая их отдельным объектом мы получаем сотрудника. Для хранения этой связки используется объект «Сотрудники». Можно было бы должность хранить и непосредственно, просо сделав поле «Должность» у объекта «Пользователи». Но это будет не грамотно. В базе данных должны использоваться справочники, а данные не должны дублироваться.
Если же использовать поле, то, например, должность «Терапевт» может быть использована по отношению ко многим пользователем. А это, во-первых, не правильно, так как возникает упомянутое дублирование данных, а во-вторых — это просто не удобно.
Дублирование было критично лет 20 назад, когда жесткие диски были малых размеров. Сейчас же при огромных объемах жестких дисков — это не является проблемой, но все же база данных должна быть построена грамотно. Ну и как я уже написал — это не удобно, у должностей как бы отсутствует стандартизация в программе. И еще, допустим Иванов работал детским терапевтом (педиатром), а теперь он перешел работать глазным терапевтом. Что будете делать в этом случае?
Менять должность ему в справочнике «Пользователи» нельзя, потому что с этой записью связано очень много других записей в базе данных. И если вы измените ему должность, то все записи об этом сотруднике в базе данных за эти два года уже будут не как о педиатре, а как о глазном терапевте. Понимаете? Нужно только создавать точно такого нового пользователя, но с должностью глазного терапевта.
Но как вы понимаете это тоже не правильно, Представляется, сколько со временем будет таких Ивановых. У них у всех будут одинаковые ФИО, даты рождения, паспортные данных и прочая информация. Поэтому такой подход является в корне не верным, несмотря на то, что многие преподаватели учебных заведений все же учат своих студентов проектировать именно так.
Поэтому все эти вещи в приведенной схеме данных выделены в отдельные объекты. То есть, в нашей схеме данных каждому человеку (пользователю) может соответствовать от одной до нескольких должностей. Даже возможно одновременно, если на второй должности человек работает по совместительству.
Точно также одной должности могут соответствовать несколько человек (пользователей). На должности хирурга может работать от одного до нескольких человек, на должности педиатра тоже самое и на должности офтальмолога, пульмонолога и т.д. — тоже самое.
Такая связь между объектами «Должности» и «Пользователи» называется много-ко-многим. И чтобы ее физически организовать, добавляют промежуточный объект в схему данных, где объединяют данные из вышеупомянутых объектов «Должности» и «Пользователи». Таким объектом в нашей схеме и является объект «Сотрудники».
Эту концепцию развиваем далее. Должности или, по другому можно сказать, врачебные специализации обычно также закрепляются за определенными кабинетами. То есть, в клинике имеется кабинет терапевта, кабинет окулиста, рентген, приемные покои, лаборатория и так далее.
Поэтому в схеме данных должна присутствовать сущность, которая будет объединять кабинеты и специализации (должности). Эта сущность называется в схеме данных «Приемный кабинет».
В каждом приемном кабинете могут располагаться от одного до нескольких врачей. Кончено это не удобно и редко практикуется в поликлиниках. Но все же, например на время ремонта или по каким то другим причинам такая ситуация встречается. Поэтому нужно сделать так, чтобы расписание приема составлялось не на кабинет в целом, а на конкретного доктора, который будет вести прием в конкретном кабинете.
Более того, следует спроектировать схему данных таким образом, чтобы в любой момент можно было в расписании изменить одного доктора на другого без ущерба предыдущим записям. это достаточно важно. Что я имею сейчас ввиду?
Давайте начнем сразу с того, что сущностью, где у нас формируется расписание будет являться одноименная сущность «Расписание». В ней объединяются сведения из сущности «Приемный кабинет» и сущности «Сотрудники».
Каждый сотрудник в своем личном кабинете сам составляет себе расписание (так же его может составлять определенное должностное лицо, которому поручено данное действие. Это все зависит от конкретной клиники).
Допустим терапевт-офтальмолог Иванов составил расписание на 01.03.2024 года и, соответственно, пациенты уже записались к нему на прием еще в конце февраля. И вдруг обнаруживается, что 01.03.2024 Иванов заболел и не может выйти на работу. Но ведь пациенты уже пришли и ждут своего приема.
С точки зрения приема граждан — это не беда, если в поликлинике есть еще один профильный врач. Он примет данных пациентов. Но вот записать в карту данные и прочие манипуляции он наверно не сможет, поскольку ему потребуется войти в личный кабинет заболевшего Иванова и от его имени вести прием. Ну а это не правильно, ведь прием пациентов — это большая ответственность. В базе будет зафиксировано, что прием вел Иванов, а на самом деле Петров.
Поэтому в своей схеме я предусмотрел такой исход событий. В этом случае в сущности «Расписание» потребуется поменять только код сотрудника. При этом никакие другие записи в базе данных затронуты не будут.
Вот если сущность «Сотрудники» была бы соединена с сущностью «Приемный кабинет», тогда смена кода сотрудника в сущности «Приемный кабинет» привела бы к искажению всех записей, которые будут в истории болезни карты пациента, ведь после смены кода сотрудника во всех прошлых записях, которые делал Иванов, будет отображен другой врач, код которого мы поставили.
Но в нашем случае этого не произойдет, поскольку мы сменим код только у конкретных записей в сущности «Расписание». Более того, мы можем сменить код сотрудника не за весь приемный день, а например, до обеда останется принимать Иванов, а после обеда — Петров. Это удобно, когда, например, Иванов, отпросился по семейным обстоятельствам или просто плохо себя почувствовал и ушел с работы с обеда. В общем, в нашей схеме можно «баловаться» временем в расписании как угодно.
Это также позволит каждому доктору (даже если оба они сидят в одном кабинете) составлять собственное расписание приема, а также «привязывать» доктора к определенному кабинету.
Вообще, расписание будет составляться на каждый рабочий день, например на неделю или две недели вперед в зависимости от внутреннего регламента поликлиники.
Для этой цели в схеме данных имеется сущность «Расписание». То есть, для каждой связки из сущности «Приемный кабинет» и «Сотрудники» приходится множество записей из сущности «Расписание». Образно говоря, для каждого специалиста в определенном кабинете есть множество записей в сущности «Расписание».
Идем дальше. В поликлинике у нас есть регистратура, где у нас хранятся карточки пациентов поликлиники. Этакая база данных регистратуры поликлиники.
Для хранения медицинских карт предусмотрена сущность «Карты». Это справочник. Далее следует важная деталь.
Пациент (то есть карта) осуществляет обращение в поликлинику и программа осуществляет его запись в сущность «Обращения» на определенную время, дату, кабинет и специалиста, представленных в сущности «Расписание».
Каждое обращение может содержать в себе несколько записей на прием. То есть, пациент Сидоров может обратиться один раз к доктору с жалобой, а после этого может быть несколько последующих приемов.
И вот каждый из таких приемов — есть запись на прием в рамках одного обращения. Поэтому сущность «Запись на прием» является подчиненной по отношению к «Обращения» и «Расписание».
По сути от «Карты» к «Обращения» идет связь один-ко-многим, так как одна и та же карта может множество раз «обращаться» за помощью в клинику. А вот от «Расписание» к «Запись на прием» может идти связь один-к-одному, так как одно и то же время на определенную дату может использоваться только один раз в сущности «Запись на прием».
Но поскольку у нас есть связка «Расписание-Обращения», то в любом случае время записи будет использовано всего один раз и связь между сущностями «Расписание» и «Запись на прием» можно оставить как один-ко-многим и это не будет являться ошибкой.
Каждое обращение пациента (не обязательно) может сопровождаться сдачей одного или нескольких анализов, поэтому сущность «Анализы пациентов» является дочерней по отношению к сущности «Обращения».
Чтобы стандартизировать названия анализов удобно использовать для этого справочник. В нем же удобно хранить и нормативные значения для каждого анализа. Ну а для того, чтобы было удобно ориентироваться большом количестве разных анализов, из удобно хранить в разрезе групп анализов. Поэтому сущность «Группы анализов» является родительской, а сущность «Анализы» — дочерней.
Сущность «Анализы пациентов» содержит в себе связку конкретной карты (через обращение) и записи на прием. Причем отметим, что от сущности «Запись на прием» к сущности «Анализы пациентов» идет две связи один-ко-многим.
То есть, поле «Код записи» сущности «Запись на прием» связано с полями «Код записи врача, назначившего анализ» и «Код записи лаборанта, добавившего результат анализа».
Так сделано по одной простой причине. В нашей системе, каждый доктор может создать записи в сущности «Анализы пациентов». То есть, указать лаборанту, какие анализы пациенту необходимо сдать.
При этом доктор может также записать пациента на сдачу анализа, например на следующий день. Следовательно в базе данных должна быть информация о том, кто назначил анализы, по какому обращению пациента ему были назначены анализы и кто вносил информацию о результате анализа.
В нашей системе вся данная информация прописывается в сущности «Анализы пациентов».
Таким образом, доктор, который назначал анализы уже в другой приемный день (доктор при первичном посещении его пациентом сам записывает пациента к себе на повторный прием на нужную дату) уже видит результат анализа, поскольку эти анализы привязаны к обращению.
Ну и наконец, получив результаты анализов (если эти анализы были необходимы) доктор устанавливает диагноз. Кстати сказать, у пациента может оказаться не один, а два и более диагнозов при комплексном заболевании, поэтому сущность «Диагнозы» является дочерней для сущности «Обращения» и «Запись на прием». Это значит, что конкретный диагноз может быть установлен для определенного обращения и был установлен в определенную дату/время, определенным специалистом.
Не всегда при каждом обращении доктор может назначить лечение, которое способно помочь пациенту. Иногда назначают повторный курс лечения или вовсе прописывают другие лекарственные препараты. Например, когда на какой то лекарственный препарат у пациента выявляется аллергическая реакция. Для этого нам потребуется сущность «Лечение».
Итак с регистрацией пациентов, болезней, диагнозами и так далее мы разобрались. Теперь давайте перейдем к регистрации оказанных услуг и продажи лекарственных препаратов в аптеке поликлиники.
Давайте начнем с оформления услуг, как с более простой компоновкой объектов будущей базы данных.
Для удобства учета услуг мы также будем хранить услуги в в составе групп, поэтому в схеме будут присутствовать такие сущности, как «Группы услуг» и «Услуги».
Стоимость услуг не является фиксированной величиной. Она время от времени меняется, поэтому для учета стоимости каждой услуги следует выделить отдельную сущность и назвать ее, например, «Стоимость услуг».
Доктор после оказания определенной услуги или комплекса медицинских услуг может выписывать квитанцию пациенту. Для хранения квитанций будет выделена отдельная сущность «Квитанции» и связана она будет с сущностью «Сотрудники», поскольку будет необходимо вести отмечать сотрудника, который сформировал квитанцию (то есть, доктора).
Ну и, соответственно, каждая квитанция будет включать в себя одну или несколько оказанных услуг. Поэтому сделаем сущность «Чек-лист услуги» и по внешним ключевым полям она будет связана с сущностью «Квитанции» и «Стоимость услуг». Ну то есть, мы должны в чек-листе отображать стоимость наших услуг.
Теперь перейдем к продаже товаров. Здесь тоже ничего сложного нет, просто будет представлено дополнительно несколько сущностей.
Начнем мы с того, что товары так же как и услуги будут учитываться в составе групп. Так будет удобно. У каждого товара есть единица измерения (шт., граммы, флаконы и так далее.).
Чтобы красиво унифицировать единицы измерения, следует для них создать отдельную сущность и связать ее с сущностью «Товары». При торговле товарами полезно иметь информацию о его производителе. Поэтому в схему базу данных включим такую сущность, как производители.
Производителя свяжем также с товарами как один-ко-многим. То есть, каждому производителю соответствует один или несколько видов товара.
Если будет желание хранить изображения для товаров, то можно в сущности товары добавить поле «Изображение», но мне кажется для изображений лучше будет выделить отдельную сущность. Это позволит для каждого товара хранить несколько изображений. Вместе с тем, если желание хранить изображения (фото товара) отсутствует — данную сущность можно не заполнять.
Идем дальше. Все товары у нас поступают от поставщиков. Поставщиками могут быть не обязательно производитель товаров. Это могут быть другие фирмы-посредники, поэтому поставщиков я выделил в отдельную сущность. Поскольку у каждого поставщика есть одно или несколько контактных лиц, с которыми можно взаимодействовать, то я выделил для их учета отдельную сущность «Контакты».
Стоит отметить, что обычно поставщики предоставляют каталог, в котором прописаны продаваемые ими товары. Поэтому мы обязательно создадим такую сущность для более полноценного учета и свяжем ее с сущностями «Поставщики» и «Товары».
Почему мы связали сущность «Каталог» с «Поставщики» я только что уже сказал, а вот почему мы связали ее с сущностью «Товары» сейчас расскажу.
Дело в том, что одинаковый товар может быть поставлен разными поставщиками. Например, «Парацетамол». Его может поставлять один поставщик, может другой и третий. Поэтому в каталоге обязательно указывается товар и поставщик. Сущностью «Каталог» создается связь много-ко-многим между сущностями «Поставщики» и «Товары».
То есть, один и тот же поставщик может поставлять разные товары, равно как и один и тот же товар может быть поставлен разными поставщиками.
Ну и, соответственно, каталожные цены также меняются время от времени, поэтому каждой позиции каталога соответствует множество цен. Учитываться программой конечно будет последняя.
Изучив каталог, ответственный сотрудник начнет составлять заявку поставщику. Для хранения заявок следует выделить сущность «Заявки», которая будет связана, соответственно с сотрудниками и поставщиками.
В заявку должны быть включены товары из каталога. Эти товары будут учитываться сущностью «Перечень товаров по заявке».
Когда товары поставщиком будут поставлены, они будут сопровождаться документацией (чаще всего накладной). И такая поставка будет учитываться сущностью «Приходная накладная». Естественно, что она связана с заявками, так как поставляют нам товар в соответствии с заявкой и с сотрудниками, поскольку нам потребуется вести учет сотрудников, которые будут принимать товар от поставщика.
При приеме товаров от поставщика может возникнуть три ситуации:
- товар полностью соответствует заявке и накладной и он полностью принят;
- товар полностью соответствует заявке и накладной, но есть брак или порча в результате транспортировки или несоответствие по количеству;
- поступили товары, которые отсутствуют в заявке.
Рассмотрим каждый из этих случаев. Когда у нас все товары соответствуют и нет порчи, то мы такие товары будем учитывать в сущности «Перечень принятого товара». Естественно, что эта сущность связана с сущностью «Приходная накладная», поскольку перечень является ее расшифровкой, а так же с сущностью — перечень товаров по заявке, поскольку товар этого перечня мы берем из заявки (у нас же разногласий по поступлению нет).
Каждый принятый товар имеет свой маркировочный номер «Код маркировки». Поэтому в данном случае мы не будем вести общий количественный учет товаров, а будем вести прием товара по штучно. То есть, мы будем будем прописывать его характеристики и указывать их в сущности «Единицы принятого товара». Обычно эти характеристики в настоящее время не вписываются вручную, а вносятся в базу данных программы с помощью сканера штрих-кода.
Все эти характеристики зашифрованы в коде маркировки аптечного препарата. Этот код маркировки присваивается. Такие коды наносит производитель, а получает он их от СБИС «Маркировка». Закон об обязательной маркировке лекарственных препаратов был принят в 2020 году.
Более подробно об этом вы можете прочитать в статье «Маркировка лекарственных средств».
Соответственно, на каждый такой товар следует установить цену реализации. Это кропотливая работа, так как приходит довольно много товара. Изначально я хотел сделать так, чтобы цена реализации устанавливалась не на каждую единицу товара, а на каждый вид товара в целом. Так установить цену намного быстрее. Но после решил сделать так, чтобы можно было устанавливать цену для каждой отдельной единицы товара. Это даст возможность манипулировать стоимостью, когда, например у товара прошло 2/3 срока годности. Он еще вполне пригоден, но для него можно установить акционную стоимость (снизить), чтобы продать.
Эти цены будут учитываться в сущности «Цены реализации». Продажи у нас будет создавать отдельный сотрудник (аптекарь). Эти продажи будут вестись в сущности «Продажи». По сути здесь будут храниться кассовые чеки.
Ну и в самом чеке у нас отображаются товары, поэтому мы эти товары учтем в сущности «Чек-лист товары».
Теперь рассмотрим случай, когда товар соответствует, но есть разногласия, например брак, разорванная упаковка или что то другое.
Будем учитывать такой товар в сущности «Перечень не принятого товара». Естественно, что он связан с накладной и с перечнем товаров по заявке.
Совершенно аналогично, что в перечне не принятого товара по заявке будут единицы не принятого товара (то есть, мы же не принимаем конкретные единицы). Например, они разбиты или у них истек срок годности…
Такие расхождения мы будем учитывать в сущности «Расхождения при поступлении», а названия таких расхождений будут храниться в справочнике «Расхождения».
На эти товары программно будет формироваться акт возврата.
Теперь посмотрим на ситуацию, когда в накладной присутствуют товары, которые мы не заказывали.
Здесь достаточно все просто. Мы не будем учитывать здесь эти товары поштучно, ведь мы не собираемся их принимать и ими торговать. Нам их при поставке в накладной прописали количественно и мы их точно также учтем в отдельной сущности и назовем ее «Перечень товаров, отсутствующих в заявке».
Ну и в общем то, все товары, которые нам нужно вернуть мы должны объединить в накладную на возврат. Для учета этой накладной у нас есть сущность «Накладная на возврат». Естественно, что в нее попадают товары из наших двух последних случаев.
Описательная характеристика нашей информационно-логической модели данных окончена. Давайте теперь перейдем к построению физической модели данных.
Далее на основе логической модели данных создается физическая модель.
Физическая модель базы данных отличается от логической тем, что она выполнена по правилам той СУБД, для которой эта база данных создается. Но физическая модель — это все же еще модель, а не сама база данных. А вот уже из физической модели мы создадим саму базу данных. Но это будет чуть дальше, а пока разберем нашу физическую модель данных.
Выберем для построения физической модели данных СУБД MySQL. Я буду делать на версии 8.0.28, но для всех остальных версий никакой принципиальной разницы не будет.
Я выбрал серверную СУБД, так как считаю выбор настольных СУБД (таких как MS Access) не совсем подходящих под эту задачу. Скорее всего, пользователей будет много и настольная СУБД здесь не подойдет. Название таблиц и поля физической модели данных я давал русскими именами, так как MySQL прекрасно работает с кириллицей. Исключением только является имя базы данных. Имя самой базы данных лучше задать латинскими буквами, так как имя, заданное кириллицей может вызвать проблемы при импорте базы данных с помощью Workbench. Больше никаких ограничений нет.
Физическая модель данных поликлиники
Структура таблицы «Корпуса»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_корпуса | Код корпуса | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Номер | Номер корпуса | INTEGER | 2 | Not Null | ||
Адрес | Адрес корпуса | VARCHAR | 255 | Not Null |
Структура таблицы «Отделения»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_отделения | Код отделения | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_корпуса | Код корпуса | INTEGER | 11 | Not Null | FK | |
Отделение | Название отделения | VARCHAR | 100 | Not Null |
Структура таблицы «Кабинеты»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_кабинета | Код кабинета | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_отделения | Код отделения | INTEGER | 11 | Not Null | FK | |
Кабинет | Номер кабинета | VARCHAR | 3 | Not Null | ||
Название | Название кабинета | VARCHAR | 100 |
Структура таблицы «Группы_анализов»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_группы | Код группы | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Группа | Название группы анализов | VARCHAR | 100 | Not Null |
Структура таблицы «Анализы»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_анализа | Код анализа | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_группы | Код группы | INTEGER | 11 | Not Null | FK | |
Анализ | Название анализа | VARCHAR | 255 | Not Null | ||
Минимальное_значение_М | Минимальное значение анализа для мужчин | DECIMAL | 10,2 | Not Null | ||
Максимальное_значение_М | Максимальное значение анализа для мужчин | DECIMAL | 10,2 | Not Null | ||
Минимальное_значение_Ж | Минимальное значение анализа для женщин | DECIMAL | 10,2 | Not Null | ||
Максимальное_значение_Ж | Максимальное значение анализа для женщин | DECIMAL | 10,2 | Not Null |
Структура таблицы «Карты»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_карты | Код карты | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
ФИО | ФИО пациента | VARCHAR | 45 | Not Null | ||
Дата_рождения | Дата рождения | DATE | Not Null | |||
Пол | Пол (М/Ж) | VARCHAR | 1 | Not Null | ||
СНИЛС | СНИЛС | VARCHAR | 14 | Not Null | ||
Паспорт | Паспортные данные | VARCHAR | 255 | Not Null | ||
Адрес | Адрес по прописке | VARCHAR | 255 | Not Null | ||
Телефон | Номер телефона в формате +7 (999) 999-99-99 | VARCHAR | 18 |
Структура таблицы «Обращения»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_обращения | Код обращения | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_карты | Код карты | VARCHAR | 11 | Not Null | FK | |
Жалоба | Жалоба пациента при обращении | DATE | Not Null | |||
Статус | Статус (открыто/закрыто) | VARCHAR | 7 | Not Null |
Структура таблицы «Группы_должностей»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_группы | Код группы | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Группа | Группа | VARCHAR | 100 | Not Null |
Структура таблицы «Должности»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_должности | Код должности | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_группы | Код группы | INTEGER | 11 | Not Null | FK | |
Должность | Название должности | VARCHAR | 100 | Not Null | ||
Статус | Статус (действующая/не действующая) | VARCHAR | 14 | Not Null |
Структура таблицы «Пользователи»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_пользователя | Код пользователя | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
ФИО | ФИО пользователя программы | VARCHAR | 45 | Not Null | ||
Дата_рождения | Дата рождения пользователя | DATE | 100 | Not Null | ||
Паспорт | Паспортные данные пользователя | VARCHAR | 255 | Not Null | ||
Статус | Статус (действующая/не действующая) | VARCHAR | 14 | Not Null | ||
Логин | Логин учетной записи | VARCHAR | 45 | Not Null | ||
Пароль | Пароль от учетной записи | VARCHAR | 45 |
Структура таблицы «Телефоны»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_телефона | Код должности | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_группы | Код группы | INTEGER | 11 | Not Null | FK | |
Должность | Название должности | VARCHAR | 100 | Not Null | ||
Статус | Статус (действующая/не действующая) | VARCHAR | 14 | Not Null |
Структура таблицы «Сотрудники»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_сотрудника | Код сотрудника | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_должности | Код должности | INTEGER | 11 | Not Null | FK | |
Код_пользователя | Код пользователя | INTEGER | 11 | Not Null | FK | |
Дата_назначения | Дата назначения пользователя на должность | DATE | Not Null | |||
Дата_увольнения | Дата увольнения | DATE | ||||
Статус | Статус (работает/уволен) | VARCHAR | 8 | Not Null |
Структура таблицы «Роли»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_роли | Код роли | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Роль | Название роли (администратор, главный врач, заместитель главного врача, работник регистратуры, доктор, менеджер склада, кассир) | VARCHAR | 100 | Not Null |
Структура таблицы «Открытые_роли»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_открытой_роли | Код открытой роли | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_роли | Код роли | INTEGER | 11 | Not Null | FK | |
Код_сотрудника | Код сотрудника | INTEGER | 11 | Not Null | FK | |
Статус | Статус (действующая/не действующая) | VARCHAR | 14 | Not Null |
Структура таблицы «Приемный_кабинет»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_приемного_кабинета | Код открытой роли | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_кабинета | Код роли | INTEGER | 11 | Not Null | FK | |
Код_должности | Код сотрудника | INTEGER | 11 | Not Null | FK | |
Статус | Статус (действует/не действует) | VARCHAR | 12 | Not Null |
Структура таблицы «Расписание»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_расписания | Код расписания | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_приемного_кабинета | Код приемного кабинета | INTEGER | 11 | Not Null | FK | |
Код_сотрудника | Код сотрудника, для которого составляется расписание | INTEGER | 11 | Not Null | FK | |
Дата | Дата приема | DATE | Not Null | |||
Время | Время приема | TIME | Not Null | |||
Статус | Статус (занято/свободно) | VARCHAR | 8 | Not Null |
Структура таблицы «Запись_на_прием»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_записи | Код записи | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_обращения | Код обращения | INTEGER | 11 | Not Null | FK | |
Код_расписания | Код расписания | INTEGER | 11 | Not Null | FK |
Структура таблицы «Диагнозы»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_диагноза | Код диагноза | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_обращения | Код обращения | INTEGER | 11 | Not Null | FK | |
Код_записи | Код записи | INTEGER | 11 | Not Null | FK | |
Диагноз | Название диагноза | VARCHAR | 255 | Not Null | ||
Примечание | Примечание | VARCHAR | 255 |
Структура таблицы «Лечение»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_лечения | Код лечения | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_диагноза | Код диагноза | INTEGER | 11 | Not Null | FK | |
Код_записи | Код записи | INTEGER | 11 | Not Null | FK | |
Лечение | Назначенное лечение | LONGTEXT | Not Null | |||
Результат | Результат лечения | VARCHAR | 255 |
Структура таблицы «Анализы_пациентов»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_анализа_пациента | Код анализа пациента | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_анализа | Код анализа | INTEGER | 11 | Not Null | FK | |
Код_обращения | Код обращения | INTEGER | 11 | Not Null | FK | |
Код_записи_врача_назначившего_анализ | Код записи врача, назначившего анализ | INTEGER | 11 | Not Null | FK | |
Код_записи_лаборанта_добавившего_результат_анализа | Код записи лаборанта, добавившего результат анализа | INTEGER | 11 | Not Null | FK | |
Дата | Дата записи лаборантом показателя анализа | DATE | ||||
Показатель | Показатель анализа | DECIMAL | 10,2 | |||
Статус | Статус (норма/отклонение) | VARCHAR | 10 |
Структура таблицы «Поставщики»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_поставщика | Код поставщика | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Полное_наименование | Полное название организации поставщика | VARCHAR | 100 | Not Null | ||
Краткое_наименование | Краткое название организации поставщика | VARCHAR | 40 | Not Null | ||
ФИО_руководителя | ФИО руководителя | VARCHAR | 45 | Not Null | ||
Адрес | Адрес | VARCHAR | 255 | Not Null | ||
ИНН | ИНН | VARCHAR | 10 | |||
КПП | КПП | VARCHAR | 9 | |||
ОГРН | ОГРН | VARCHAR | 13 | |||
Примечание | Примечание | VARCHAR | 255 | |||
Сайт | Сайт организации | VARCHAR | 70 |
Структура таблицы «Контакты»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_контакта | Код контакта | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_поставщика | Код поставщика | INTEGER | 11 | Not Null | FK | |
ФИО | ФИО контактного лица | VARCHAR | 45 | Not Null | ||
Должность | Должность | VARCHAR | 100 | |||
Телефон | Телефон | VARCHAR | 18 | |||
E_mail | адрес электронной почты контактного лица | VARCHAR | 70 |
Структура таблицы «Заявки»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_заявки | Код заявки | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_поставщика | Код поставщика, которому составляется заявка | INTEGER | 11 | Not Null | FK | |
Код_сотрудника | Код сотрудника, составлявшего заявку | INTEGER | 11 | Not Null | FK | |
Номер | Номер заявки | INTEGER | 11 | Not Null | ||
Дата | Дата заявки | DATE | Not Null |
Структура таблицы «Поставщики»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_поставщика | Код поставщика | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Полное_наименование | Полное название организации поставщика | VARCHAR | 100 | Not Null |
Структура таблицы «Приходная_накладная»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_накладной | Код накладной | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_заявки | Код заявки, по которой поступила накладная | INTEGER | 11 | Not Null | FK | |
Код_сотрудника | Код сотрудника, которые принимает товары по накладной | INTEGER | 11 | Not Null | FK | |
Номер | Номер накладной | VARCHAR | 20 | Not Null | ||
Дата | Дата накладной | DATE | Not Null | |||
Статус | Статус (полная/частичная/не соответствует) | VARCHAR | 9 | Not Null |
Поле «Статус» может иметь одно из трех значений (Полная/Частичная/Не соответствует):
- Полноная — это когда все товары привезли, которые заказывали;
- Частичная — когда часть товаров. То есть, одну заявку можно разбить на несоклько накладных с разным привозом;
- Не соответствует — когда в накладной присутствует любое несоответствие товара/порча/явный визуальный брак и т.п.
Структура таблицы «Накладная_на_возврат»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_накладной | Код накладной на возврат | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_сотрудника | Код сотрудника, оформляющего возврат | INTEGER | 11 | Not Null | FK | |
Номер | Номер накладной на возврат | VARCHAR | 20 | Not Null | ||
Дата | Дата накладной на возврат | DATE | Not Null |
Структура таблицы «Перечень_товаров_отсутствующих_в_заявке»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_товара_отсутствующего_в_заявке | Код товара, отсутствующего в заявке | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_накладной_на_возврат | Код накладной на возврат | INTEGER | 11 | Not Null | FK | |
Код_приходной_накладной | Код приходной накладной | INTEGER | 11 | Not Null | FK | |
Товар | Название возвращаемого товара (как в приходной накладной) | VARCHAR | 100 | Not Null | ||
Количество | Количество возвращаемого товара | INTEGER | 11 | Not Null |
Структура таблицы «Перечень_не_принятого_товара»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_не_принятого_товара | Код не принятого товара | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_накладной | Код приходной накладной | INTEGER | 11 | Not Null | PK | |
Код_позиции_в_перечне_по_заявке | Код позиции в перечне по заявке | INTEGER | 11 | Not Null | PK |
Структура таблицы «Единицы_не_принятого_товара_по_заявке»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_единицы_товара | Код единицы товара | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_не_принятого_товара | Код не принятого товара | INTEGER | 11 | Not Null | FK | |
Код_маркировки | Код маркировки товара (наносится производителем) | VARCHAR | 83 | |||
Дата_изготовления | Дата п роизводства товара | DATE | Not Null | |||
Дата_окончания_годности | Дата окончания срока годности товара | DATE | Not Null | |||
Серийный_номер | Серийный номер товара | VARCHAR | 45 | |||
Номер_партии | Номер партии выпуска товара | VARCHAR | 45 |
Структура таблицы «Расхождения»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_расхождения | Код расходения | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Расхождение | Название расхождения | VARCHAR | 100 | Not Null |
Структура таблицы «Расхождения_при_поступлении»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_расхождения_при_поступлении | Код расхождения при поступлении | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_расхождения | Код расхождения | INTEGER | 11 | Not Null | FK | |
Код_единицы_товара | Код единицы товара, у которого выявлено расхождение | INTEGER | 11 | Not Null | FK |
Структура таблицы «Перечень_накладной_на_возврат_товаров_по_заявке»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_позиции | Код позиции | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_накладной | Код накладной на возврат | INTEGER | 11 | Not Null | FK | |
Код_единицы_товара | Код единицы не принятого товара по заявке | INTEGER | 11 | Not Null | FK |
Структура таблицы «Производители»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_производителя | Код производителя | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Производитель | Название производителя | VARCHAR | 100 | Not Null | ||
Адрес | Адрес | VARCHAR | 255 | |||
ИНН | ИНН | INTEGER | 10 | |||
КПП | КПП | INTEGER | 9 | |||
ОГРН | ОГРН | INTEGER | 13 |
Структура таблицы «Единицы_измерения»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_единицы_измерения | Код единицы измерения | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Единица_измерения | Название единицы измерения | VARCHAR | 100 | Not Null |
Структура таблицы «Группы_товаров»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_группы | Код поставщика | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Группа | Полное название организации поставщика | VARCHAR | 100 | Not Null |
Структура таблицы «Товары»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_товара | Код товара | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_группы | Код группы | INTEGER | 11 | Not Null | FK | |
Код_единицы_измерения | Код единицы измерения | INTEGER | 11 | Not Null | FK | |
Код_производителя | Код производителя | INTEGER | 11 | Not Null | FK | |
Номенклатурный_номер | Номенклатурный номер (внутриорганизационный номенклатурный номер товара) | INTEGER | 11 | Not Null | ||
Товар | Название товара | VARCHAR | 100 | Not Null | ||
Назначение | Назначение товара | LONGTEXT | ||||
Способ_применения_и_дозы | Способ применения и дозы (справедливо для лекарственных препаратов) | LONGTEXT | ||||
Описание | Описание товара | LONGTEXT |
Структура таблицы «Изображения»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_изображения | Код изображения | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_товара | Код товара | INTEGER | 11 | Not Null | FK | |
Изображение | Изображение товара | LONGBLOB | Not Null |
Структура таблицы «Каталог»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_артикула | Код артикула | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_поставщика | Код поставщика | INTEGER | 11 | Not Null | FK | |
Код_товара | Код товара | INTEGER | 11 | Not Null | FK | |
Артикул | Каталожный артикул товара | VARCHAR | 20 | Not Null |
Структура таблицы «Цены»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_цены | Код цены | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_артикула | Код артикула | INTEGER | 11 | Not Null | FK | |
Цена | Каталожная цена товара | DECIMAL | 10,2 | Not Null | ||
Дата_установления | Дата установления цены | DATE | Not Null |
У каждого товара в разных каталогах одного и того же поставщика цена на товар может меняться, поэтому целесообразно иметь таблицу «Цены», где будет вестись учет текущих каталожных цен.
Структура таблицы «Перечень_товаров_по_заявке»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_позиции_в_перечне_по_заявке | Код позиции в перечне по заявке | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_заявки | Код заявки | INTEGER | 11 | Not Null | FK | |
Код_цены | Код цены | INTEGER | 11 | Not Null | FK | |
Количество | Количество | INTEGER | 11 |
В данной таблице поле «Количество» можно не заполнять, так как количество можно узнать по числу записей дочерней таблицы с соответствующим кодом позиции в перечне по заявке. Но я добавил это поле для того, чтобы все-таки было проще составлять запрос на выборку там, где фигурирует данная таблица.
Структура таблицы «Перечень_принятого_товара»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_принятого_товара | Код принятого товара | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_накладной | Код накладной | INTEGER | 11 | Not Null | FK | |
Код_позиции_в_перечне_по_заявке | Код позиции в перечне по заявке | INTEGER | 11 | Not Null | FK |
Структура таблицы «Единицы_принятого_товара»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_единицы_товара | Код единицы товара | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_принятого_товара | Код принятого товара | INTEGER | 11 | Not Null | FK | |
Код_маркировки | Код маркировки | VARCHAR | 83 | FK | ||
Дата_изготовления | Дата производства товара | DATE | Not Null | |||
Дата_окончания_годности | Дата окончания срока годности товара | DATE | Not Null | |||
Серийный_номер | Серийный номер | VARCHAR | 45 | |||
Номер_партии | Номер партии | VARCHAR | 45 | |||
Статус | Статус (продан/не продан) | VARCHAR | 9 |
Поле «Статус» может содержать одно из двух значений — продан/не продан
Это поле удобно использовать для того, чтобы считать остаток по товару. То есть, можно выводить запросом все товары с нужным названием, у которых статус «Не продано». Причем здесь можно будет выводить остаток как по отдельным поступлениям конкретного товара, так и по всем поступлениям одного вида товара.
Структура таблицы «Продажи»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Номер_чека | Номер кассового чека | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_сотрудника | Код сотрудника, который продает товар | INTEGER | 11 | Not Null | FK | |
Дата | Дата продажи | DATE | Not Null |
Структура таблицы «Цены_реализации»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_цены | Код цены | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_единицы_товара | Код отдельной единицы товара | INTEGER | 11 | Not Null | FK | |
Цена | Цена реализации | DECIMAL | 10,2 | Not Null | ||
Дата_установления | Дата установления цены | DATE | Not Null |
Структура таблицы «Чек_лист_товары»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_позиции | Код позиции в чеке | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_цены | Код цены | INTEGER | 11 | Not Null | FK | |
Номер_чека | Номер чека | INTEGER | 11 | Not Null | FK |
Структура таблицы «Группы_услуг»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_группы | Код группы услуг | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Группа | Название группы услуг | VARCHAR | 100 | Not Null |
Структура таблицы «Услуги»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_услуги | Код услуги | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_группы | Код группы услуг | INTEGER | 11 | Not Null | FK | |
Услуга | Название услуги | VARCHAR | 100 | Not Null | ||
Описание | Описание услуги | LONGTEXT |
Структура таблицы «Стоимость_услуг»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_стоимости | Код стоимости | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_услуги | Код услуги | INTEGER | 11 | Not Null | FK | |
Стоимость | Стоимость услуги | DECIMAL | 10,2 | Not Null | ||
Дата_установления | Дата установления | DATE | Not Null |
Структура таблицы «Квитанции»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_квитанции | Код квитанции | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_сотрудника | Код сотрудника, сформировавшего квитанцию (код доктора) | INTEGER | 11 | Not Null | FK | |
Дата_формирования | Дата формирования квитанции | DATE | Not Null | |||
Дата_оплаты | Дата оплаты квитанции | DATE | ||||
Статус | Статус (оплачено/не оплачено) | VARCHAR | 11 | Not Null |
Структура таблицы «Чек_лист_услуги»
Идентификатор поля | Наименование поля | Тип поля | Размер | Значение по умолчанию | Условие на значение | Ключ |
Код_поцизии | Код позиции | INTEGER | 11 | Счетчик | Уникальное, Not Null | PK |
Код_квитанции | Код квитанции | INTEGER | 11 | Not Null | FK | |
Код_стоимости | Код стоимости | INTEGER | 11 | Not Null | FK |
Итак, мы разработали физическую модель базы данных. Этап проектирования мы закончили. Теперь давайте на примере пары таблиц рассмотрим, как создать базу данных нашей поликлиники с использованием нашей физической модели.
Создание базы данных поликлиники
Итак, открываем с вами Workbench и выбираем команду File/New Model. Далее мы меняем имя нашей схемы данных (в MySQL база данных называется схемой), например, на clinic. Регистр значения не имеет.
Далее создаем все перечисленные 50 таблиц, опираясь на нашу вышеописанную физическую модель данных. Создадим, например, таблицу «Анализы». Заполните все поля, как указано ниже на рисунке, используя при этом данные физической модели данных. Для этого закрываем эту вкладку и нажимаем Add Table, чтобы создать первую таблицу.
Аббревиатуры:
— PK — признак первичного ключа для поля;
— NN — поле не может быть пустым;
— AI — поле будет автоинкрементным. Используется совместно с первичным ключом.
Теперь перейдем на вкладку Foreign Keys для того, чтобы задать внешний ключ для нашей таблицы. Внешний ключ — это поле, которое будет соединять нашу таблицу с родительской. Из логической схемы данных мы помним, что таблица «Анализы» является дочерней по отношению к таблице «Группы анализов». Из этого следует, что наш внешний ключ должен указывать на первичный ключ таблицы «Группы анализов».
В столбце Foreign Key Name мы укажем имя нашего внешнего ключа. Мне нравится называть внешние ключи с использованием названий двух таблиц. Например, здесь я объединяю две таблицы «Группы анализов» и «Анализы» и поэтому свой ключ я называю «Группы_Анализы». Можно было бы назвать как «ГруппыАнализов_Анализы». Ну просто MySQL покажет вам ошибку при создании самой базы данных, если название ключа окажется слишком длинным.
В столбце Reference Table указываем таблицу, на которую ссылается наш внешний ключ. Это у нас таблица «Группы анализов». Выбираем ее из списка. А справа у нас появляются два столбца. В левом из них представлены поля таблицы «Анализы», а в правом лишь одно поле первичного ключа из таблицы «Группы анализов». Это поле нужно выбрать из списка.
Стоит еще установить триггеры для этой таблицы, которые будут срабатывать при обновлении у удалении данных из родительской таблицы. Установим значение Cascade. Это значит, что при удалении данных из родительской таблицы, будут удалены соответствующие данные и из дочерней таблицы. То есть, если мы удалим группу из таблицы «Группы анализов», то из дочерней таблицы «Анализы» будут удалены все анализы, которые входили в удаленную группу. Тоже самое и с обновлением данных.
Все остальные таблицы создаем по данному примеру, используя логическую и физическую модели данных. Затем будет удобно создать EER-диаграмму для наших таблиц. Это тоже самое, что мы делали в логической модели данных, так сказать, на бумаге, только теперь это будет в системе Workbench. Для этого нажмите на EER Diagram.
В новом появившемся окне сразу нужно выбрать команду Model / Diagram Properties And Size для того, чтобы задать высоту и ширину поля диаграммы в листах. Сделайте сразу 3 на 3 листа, потому что диаграмма будет большой.
После этого все созданные таблицы следует перетащить на пустой лист диаграммы и на этом листе таблицы отобразятся уже со связями.
Последним шагом в создании базы данных будет являться генерирование скрипта база данных. Скрипт представляет из себя команды языка SQL, которые создают нашу базу данных на основе только что созданных таблиц в Workbench.
Ну то есть, Workbench — это визуальный редактор базы данных. Чтобы нам руками в текстовом файле не писать большое количество команд, за нас это сделает Workbench. Мы лишь создали в нем в визуальном режиме таблицы, а скрипт сгенерируем командой: File/Export/Forward Engineer SQL Create Script.
Укажите папку, куда вы хотите сохранить скрипт и жмите до конца Next, пока не сгенерируется скрипт в указанной папке.
Теперь в Workbench откройте соединение и запустите этот скрипт и вы получите базе данных у себя на компьютере.
Кстати говоря, наша схема данных может быть значительно сокращена. Например, если вам не нужен учет оказанных услуг или учет продаж товаров, то вы легко можете удалить эти таблицы из схемы данных, ну либо просто не использовать эти таблицы в программе.
Создание базы данных поликлиники — это трудоемкий процесс и, если вы не хотите тратить время на это, то вы можете скачать уже готовый скрипт по ссылке ниже.
Скачать готовую базу данных поликлиники (больницы)
Скрипт модели базы данных поликлиники в формате MySQL
Данный скрипт получен на основе модели базы данных поликлиники, спроектированный в MySQL Workbench и экспортированный в формат файла .sql. Вы можете запустить этот скрипт на выполнение, например, в той же среде MySQL Workbench для того, чтобы из этого скрипта сгенерировалась база данных на вашем жестком диске или просто импортировать его на свой компьютер.
Скачать скрипт базы данных поликлиники в формате MySQL
База данных поликлиники (больницы) в формате MS Access
Скачать базу данных поликлиники в формате MS Access (формат будет доступен чуть позже).