Как вы храните бизнес-операции в базе данных SQL? - PullRequest
0 голосов
/ 19 декабря 2009

Целью является хранение таких действий, как вставка, обновление и удаление бизнес-записей.

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

CREATE TABLE ActivityTypes
(
    TypeId              int IDENTITY(1,1)       NOT NULL,
    TypeName            nvarchar(50)            NOT NULL,

    CONSTRAINT PK_ActivityTypes          PRIMARY KEY (TypeId),
    CONSTRAINT UK_ActivityTypes          UNIQUE (TypeName)
)

INSERT INTO ActivityTypes (TypeName) VALUES ('WidgetRotated');
INSERT INTO ActivityTypes (TypeName) VALUES ('WidgetFlipped');
INSERT INTO ActivityTypes (TypeName) VALUES ('DingBatPushed');
INSERT INTO ActivityTypes (TypeName) VALUES ('ButtonAddedToDingBat');

CREATE TABLE Activities
(
    ActivityId          int IDENTITY(1,1)       NOT NULL,
    TypeId              int                     NOT NULL,
    AccountId           int                     NOT NULL,
    TimeStamp           datetime                NOT NULL,

    CONSTRAINT PK_Activities                      PRIMARY KEY (ActivityId),
    CONSTRAINT FK_Activities_ActivityTypes        FOREIGN KEY (TypeId)
                                                  REFERENCES ActivityTypes (TypeId),
    CONSTRAINT FK_Activities_Accounts             FOREIGN KEY (AccountId)
                                                  REFERENCES Accounts (AccountId)
)

CREATE TABLE WidgetActivities
(
    ActivityId          int                     NOT NULL,
    WidgetId            int                     NOT NULL,

    CONSTRAINT PK_WidgetActivities                  PRIMARY KEY (ActivityId),
    CONSTRAINT FK_WidgetActivities_Activities       FOREIGN KEY (ActivityId)
                                                    REFERENCES Activities (ActivityId),
    CONSTRAINT FK_WidgetActivities_Widgets          FOREIGN KEY (WidgetId)
                                                    REFERENCES Widgets (WidgetId)
)

CREATE TABLE DingBatActivities
(
    ActivityId          int                     NOT NULL,
    DingBatId           int                     NOT NULL,
    ButtonId            int,

    CONSTRAINT PK_DingBatActivities                  PRIMARY KEY (ActivityId),
    CONSTRAINT FK_DingBatActivities_Activities       FOREIGN KEY (ActivityId)
                                                     REFERENCES Activities (ActivityId),
    CONSTRAINT FK_DingBatActivities_DingBats         FOREIGN KEY (DingBatId)
                                                     REFERENCES DingBats (DingBatId)
    CONSTRAINT FK_DingBatActivities_Buttons          FOREIGN KEY (ButtonId)
                                                     REFERENCES Buttons (ButtonId)
)

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

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

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

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

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

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

Ответы [ 5 ]

1 голос
/ 19 декабря 2009

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

CREATE TABLE Objects   -- Bad table name, should be more specific
(
     object_id     INT          NOT NULL,
     name          VARCHAR(20)  NOT NULL,
     CONSTRAINT PK_Application_Objects PRIMARY KEY CLUSTERED (application_id)
)

CREATE TABLE Widgets
(
     object_id     INT           NOT NULL,
     height        DECIMAL(5, 2) NOT NULL,
     width         DECIMAL(5, 2) NOT NULL,
     CONSTRAINT PK_Widgets PRIMARY KEY CLUSTERED (object_id),
     CONSTRAINT FK_Widgets_Objects
     FOREIGN KEY (object_id) REFERENCES Objects (object_id)
)

CREATE TABLE Dingbats
(
     object_id     INT           NOT NULL,
     label         VARCHAR(50)   NOT NULL,
     CONSTRAINT PK_Dingbats PRIMARY KEY CLUSTERED (object_id),
     CONSTRAINT FK_Dingbats_Objects
     FOREIGN KEY (object_id) REFERENCES Objects (object_id)
)

Теперь для вашей деятельности:

CREATE TABLE Object_Activities
(
     activity_id     INT          NOT NULL,
     object_id       INT          NOT NULL,
     activity_type   INT          NOT NULL,
     activity_time   DATETIME     NOT NULL,
     account_id      INT          NOT NULL,
     CONSTRAINT PK_Object_Activities PRIMARY KEY CLUSTERED (activity_id),
     CONSTRAINT FK_Object_Activities_Objects
     FOREIGN KEY (object_id) REFERENCES Objects (object_id),
     CONSTRAINT FK_Object_Activities_Activity_Types
     FOREIGN KEY (activity_type) REFERENCES Activity_Types (activity_type),
)

CREATE TABLE Dingbat_Activities
(
     activity_id     INT     NOT NULL,
     button_id       INT     NOT NULL,
     CONSTRAINT PK_Dingbat_Activities PRIMARY KEY CLUSTERED (activity_id),
     CONSTRAINT FK_Dingbat_Activities_Object_Activities
     FOREIGN KEY (activity_id) REFERENCES Object_Activities (activity_id),
     CONSTRAINT FK_Dingbat_Activities_Buttons
     FOREIGN KEY (button_id) REFERENCES Object_Activities (button_id),
)

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

Вот предостережение big : убедитесь, что объекты / действия действительно имеют что-то общее, что их связывает, и требует, чтобы вы пошли по этому пути. Вы не хотите хранить несвязанные, несвязанные данные в одной таблице. Например, вы можете использовать этот метод для создания таблицы, в которой будут храниться как транзакции с банковскими счетами, так и небесные события, но это не очень хорошая идея. На базовом уровне у них должно быть что-то общее.

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

1 голос
/ 19 декабря 2009

Я собираюсь выйти на конечность и сделать несколько диких догадок о том, чего вы действительно пытаетесь достичь.

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

Хорошо, для этих действий вам нужно несколько разных таблиц: одна для инвентаря, одна для отделов и одна для сотрудников

Таблица инвентаризации может содержать следующую информацию:

inventory:
  item_id (pk)
  description (varchar)
  number_in_stock (number)
  cost_wholesale (number)
  retail_price (number)
  dept_id (fk)

department:
  dept_id (pk)
  description (varchar)

employee
  emp_id (pk)
  first_name (varchar)
  last_name (varchar)
  salary (number)
  hire_date (date)
  fire_date (date)

Итак, когда вы покупаете новые предметы, вы либо обновляете number_in_stock в таблице инвентаря, либо создаете новую строку, если это предмет, которого у вас никогда не было раньше. Когда вы продаете предмет, вы декрицируете number_in_stock для этого предмета (также когда вы списываете предмет).

Когда вы нанимаете нового сотрудника, вы добавляете запись о нем в таблицу сотрудников. Когда вы платите им, вы берете их зарплату из столбца зарплаты. Когда вы их увольняете, вы заполняете этот столбец для их записи (и прекращаете платить им).


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

При проектировании базы данных вам нужно задать вопрос не «что мне нужно делать?» это «Какую информацию мне нужно отслеживать?»

1 голос
/ 19 декабря 2009

Новый ответ, основанный на другой интерпретации вопроса.

Вы просто пытаетесь составить список того, что произошло? Если вам просто нужен упорядоченный список прошлых событий, вам просто нужна 1 таблица для него:

action_list
  action_list_id (pk)
  action_desc (varchar)

event_log:
  event_log_id (pk)
  event_time (timestamp)
  action_list_id (fk)
  new_action_added (fk)
  action_details_or_description (varchar)

В этом списке action_list будет что-то вроде:

1   'WidgetRotated'
2   'WidgetFlipped'
3   'DingBatPushed'
4   'AddNewAction'
5   'DeleteExistingAction'

Event_log - это список того, что и когда происходило. Одним из ваших действий будет «добавить новое действие» и потребуется заполнить столбец «new_action_added» в таблице событий каждый раз, когда предпринимаемое действие «добавить новое действие».

Вы можете создавать действия для обновления, удаления, добавления и т. Д.

EDIT: Я добавил столбец action_details_or_description к событию. Таким образом, вы можете предоставить дополнительную информацию о действии. Например, если у вас есть действие «изменение цвета товара», описание может быть «красным» для нового цвета.

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

0 голосов
/ 19 декабря 2009

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

0 голосов
/ 19 декабря 2009

Как насчет журналов SQL?

...