Как лучше всего сохранить эту схему понятной? - PullRequest
9 голосов
/ 30 марта 2011

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

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

enter image description here

Внезапно я понимаю, что эта схема может иметь один и тот же тег в нескольких таблицах.Например, тег 123 может быть в C и B одновременно.Это невозможно, потому что каждый тег можно просто прикрепить к одному объекту.

Проще говоря, я хочу, чтобы каждый тег не появлялся в базе данных более одного раза.

Мой текущий подходenter image description here

Что я действительно хочу enter image description here

Обновление: Да, TagID выбран конечным пользователем.Кроме того, TagID предоставляется устройством чтения тегов, а TagID является 128-битным числом.

Новое обновление: Объекты до сих пор:

- Medicament (TagID, имя_объекта, общее имя, сумма, ...)

- Аппарат (TagID, имя, описание, модель, производитель, ...)

- Пациент (TagID, firstName,lastName, birthday, ...)

Все атрибуты (столбцы или как вы их называете) очень разные.

Обновление после обновления

Я работаю над системой с RFID-метками для больницы.Каждый RFID-тег прикрепляется к объекту, чтобы следить за ним, и, к сожалению, каждый объект имеет множество различных атрибутов.

Объектом может быть человек, машина или лекарство, или, возможно, новый объект с другимАтрибуты.

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

Примеры:

Tag(TagID)
Medicine(generic_name, comercial_name, expiration_date, dose, price, laboratory, ...)
Machine(model, name, description, price, buy_date, ...)
Patient(PatientID, first_name, last_name, birthday, ...)

Мы должны связать только один тег для одного объекта.

Примечание: я недействительно говорю (или пишу) действительно: P извините за это.Не носитель языка здесь.

Ответы [ 7 ]

7 голосов
/ 05 апреля 2011

Вы можете применять эти правила, используя реляционные ограничения.Проверьте использование постоянного столбца для применения ограничения Tag: {Pencil or Computer} .Эта модель дает вам большую гибкость для моделирования каждой дочерней таблицы (Person, Machine, Pencil и т. Д.) И в то же время предотвращает любые конфликты между тегами.Также хорошо, что нам не нужно прибегать к триггерам или udfs с помощью проверочных ограничений, чтобы обеспечить соблюдение отношения.Отношение встроено в модель.

diagram

create table dbo.TagType (TagTypeID int primary key, TagTypeName varchar(10));
insert into dbo.TagType
    values(1, 'Computer'), (2, 'Pencil');

create table dbo.Tag
(   TagId       int primary key, 
    TagTypeId   int references TagType(TagTypeId), 
    TagName     varchar(10),
    TagDate     datetime,
    constraint UX_Tag unique (TagId, TagTypeId)
)
go
create table dbo.Computer 
(   TagId       int primary key, 
    TagTypeID   as 1 persisted,
    CPUType     varchar(25),
    CPUSpeed    varchar(25), 
    foreign key (TagId, TagTypeID) references Tag(TagId, TagTypeID)
)
go
create table dbo.Pencil 
(   TagId       int primary key, 
    TagTypeId   as 2 persisted,
    isSharp     bit,
    Color       varchar(25),
    foreign key (TagId, TagTypeID) references Tag(TagId, TagTypeId)
)
go



-----------------------------------------------------------
-- create a new tag of type Pencil:
-----------------------------------------------------------
insert into dbo.Tag(TagId, TagTypeId, TagName, TagDate)
    values(1, 2, 'Tag1', getdate());

insert into dbo.Pencil(TagId, isSharp, Color)
    values(1, 1, 'Yellow');

-----------------------------------------------------------
-- try to make it a Computer too (fails FK)
-----------------------------------------------------------
insert into dbo.Computer(TagId, CPUType, CPUSpeed)
    values(1, 'Intel', '2.66ghz')
3 голосов
/ 01 апреля 2011

поговорил с Разом, чтобы выяснить, что он пытается сделать.Он хочет гибкий способ хранения атрибутов, связанных с тегами.Теги могут относиться к одному из нескольких типов объектов, и каждый объект имеет определенный список атрибутов.он также хочет иметь возможность добавлять объекты / атрибуты без необходимости изменения схемы.вот модель, которую я придумал:

Model

3 голосов
/ 30 марта 2011

Иметь таблицу тегов с идентификационной вставкой PK TagID. Это гарантирует, что каждый TagID будет отображаться только один раз, независимо от того, что ...

Затем в таблице тегов есть столбец TagType, который может иметь произвольную форму (TableName) или, что еще лучше, иметь таблицу TagType с записями A, B, C, а затем иметь FK в теге, указывающем TagType.

Я бы переместил атрибуты тега в таблицу A, B, C, чтобы минимизировать дополнительные данные в теге, или чтобы имелась серия соединительных таблиц между тегом и A, B и C

EDIT: Предполагая, что TagID создан при создании объекта, это будет работать нормально (сначала вставьте в Tag, чтобы получить TagID и захватите его, используя IDENTITY_INSERT) Это предполагает, что пользователи не могут редактировать сам TagID.

Если пользователи могут выбрать TagID, все равно используйте Таблицу тегов с TagID, но есть еще одно поле с именем DisplayID, где пользователь может ввести число. Просто наложите уникальное ограничение на Tag.DisplayID ....

EDIT: Какие атрибуты вам нужны и могут ли они быть обнуляемыми? Если они различны для A, B и C, то лучше поместить их в A, B и C, особенно если они могут быть для A и B, но не для C ...

2 голосов
/ 02 апреля 2011

Я бы занялся этим, используя ваши оригинальные структуры. Реляционные базы данных намного лучше агрегируют / объединяют атомарные данные, чем при анализе сложных структур данных.

  • Сохраните дизайн каждого типа объекта с возможностью тегирования в отдельной таблице. Типы данных, проверочные ограничения, значения по умолчанию и т. Д. Все еще легко реализуются таким образом. Кроме того, продолжайте определять FK из каждой таблицы объектов в таблицу тегов.

  • Я предполагаю, что у вас уже есть это, но если вы наложите уникальное ограничение на столбец TagId в каждой из таблиц объектов (A, B, C и т. Д.), То вы можете гарантировать уникальность в пределах этот тип объекта.

  • Нет встроенных ограничений SQL Server, гарантирующих уникальность среди всех типов объектов, если они реализованы в виде отдельных таблиц. Таким образом, вам придется сделать свою собственную проверку. Триггер INSTEAD OF в ваших объектных таблицах может сделать это чисто.

Сначала создайте представление для доступа к списку TagId для всех ваших таблиц объектов.

CREATE VIEW TagsInUse AS
    SELECT A.TagId FROM A
    UNION
    SELECT B.TagId FROM B
    UNION
    SELECT C.TagId FROM C
;

Затем для каждой из ваших таблиц объектов определите триггер INSTEAD OF для проверки вашего TagId.

CREATE TRIGGER dbo.T_IO_Insert_TableA ON dbo.A
    INSTEAD OF INSERT
    AS
    IF EXISTS (SELECT 0 FROM dbo.TagsInUse WHERE TagId = inserted.TagId)
    BEGIN;
        --The tag(s) is/are already in use. Create the necessary notification(s).
        RAISERROR ('You attempted to re-use a TagId. This is not allowed.');
        ROLLBACK
    END;
    ELSE
    BEGIN;
        --The tag(s) is/are available, so proceed with the INSERT.
        INSERT INTO dbo.A (TagId, Attribute1, Attribute2, Attribute3)
            SELECT  i.TagId, i.Attribute1, i.Attribute2, i.Attribute3
            FROM    inserted AS i
        ;
    END;
GO

Имейте в виду, что вы также можете (и, вероятно, должны) инкапсулировать этот тест IF EXISTS в функцию T-SQL по причинам обслуживания и производительности.

Вы можете написать дополнительные хранимые процедуры для таких вещей, как поиск типа объекта, с которым связан TagId.

Плюсы

  • Вы по-прежнему пользуетесь функциями целостности данных SQL Server, которые достаточно быстры и самодокументированы. Не стоит недооценивать полезность типов данных.

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

  • Ваши опции остаются открытыми ...

Поскольку вы не сохранили все в удобном для EAV столбце nvarchar (300), вы можете настроить типы данных так, чтобы это имело смысл для каждого атрибута.

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

Вы (или ваш администратор БД) можете переместить таблицы объектов в разные группы файлов на разных дисках, если вам нужно сбалансировать ситуацию и помочь с параллельным дисковым вводом / выводом. Думайте об этом как о форме горизонтального разделения. Например, если у вас в 8 раз больше RFID-меток, примененных к контейнерам с лекарствами, чем у пациентов, вы можете поместить таблицу лекарств на другой диск, не создавая функцию разделения, которая вам понадобится для монолитной таблицы (одна таблица). для всех типов).

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

Наиболее важно , реализация различных бизнес-правил, основанных на типе объекта, на намного проще. Вам не нужно реализовывать какую-либо неприятную условную логику, такую ​​как «ЕСЛИ тип =« игла »ТОГДА ... ИЛИ ЕСЛИ« тип »=« пациент »ТОГДА… ЕЩЕ« ЕСЛИ… ». Если вам нужно применить другие правила, примените их к соответствующей таблице объектов, не проверяя значение типа.

Против

  • Триггеры должны поддерживаться. Однако в любом случае это должно быть сделано в вашем приложении, поэтому вы выполняете ту же проверку целостности данных в базе данных. Это означает, что у вас не будет никаких дополнительных сетевых издержек, и это будет доступно для любого приложения, которое использует эту базу данных.
2 голосов
/ 30 марта 2011

если каждый тег может быть только в a, b или c только один раз, я бы просто объединил a, b и c в одну таблицу. было бы проще дать вам лучшее представление о том, как построить схему, если бы вы дали пример того, что именно вы хотите собрать.

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

1 голос
/ 07 апреля 2011

То, что вы описываете, является классическим отображением ORM "таблица на тип". Entity Framework имеет встроенную поддержку этого, что вы должны посмотреть.

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

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

Реализация его в виде одной таблицы также экономит ваше дисковое пространство, поскольку вы можете реализовать уровни наследования - например, «пациент» и «доктор» и «медсестра» могут быть трех разных типов объектов, каждый из которых имеет схожие поля (например, имя, фамилия и т. д.) и некоторые уникальные поля. Сейчас вам понадобятся три таблицы с дублированными полями.

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

Единственная причина, по которой вы не будете использовать одну таблицу, заключается в том, что количество полей делает строку слишком большой, чтобы уместиться внутри страницы SQL-сервера (я считаю, что это 8 КБ). Тогда SQL будет жаловаться и не позволит вам добавить больше полей. В данном случае решение состоит в том, чтобы применить инструмент ORM (например, Entity Framework), а затем «повторно использовать» поля. Например, если «Поле1» используется только типом объекта № 1, нет никаких причин, по которым тип объекта № 3 не может использовать его для хранения чего-либо. Вам нужно только уметь различать его в своих программах.

0 голосов
/ 30 марта 2011

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

Tags
-
ID
Type (A,B, or C)
A (nullable)
B (nullable)
C (nullable)

A
-
ID
(other attributes)
...