如何在 SQL 数据库中存储业务活动?
-
20-09-2019 - |
题
目标是存储插入、更新和删除业务记录等活动。
我正在考虑的一种解决方案是对每个要跟踪的记录使用一个表。这是一个简化的示例:
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)
)
此解决方案似乎适合获取给定小部件或 dingbat 记录 ID 的所有活动,但对于获取所有活动然后尝试确定它们引用的记录似乎不太好。
也就是说,在此示例中,所有帐户名称和时间戳都存储在单独的表中,因此可以轻松创建专注于用户和时间间隔的报告,而无需知道具体的活动是什么。
但是,如果您确实想特别按类型报告活动,则此解决方案需要确定常规活动表引用的活动类型。
我可以将所有活动类型放在一张表中,但是 ID 无法受到外键的约束,而是可以将表名称用作 ID,这将导致我使用动态查询。
请注意,在示例中,DingBatActivity 有一个可选的按钮 ID。如果按钮名称在添加到 dingbat 后进行了编辑,则活动将能够引用该按钮并知道其名称,因此,如果报告按名称列出了 dingbat 和按钮的所有活动,则按钮名称会更改将自动反映在活动描述中。
寻找一些其他想法以及这些想法如何在编程工作、数据完整性、性能和报告灵活性之间进行折衷。
解决方案
的方式,我通常建筑师到这个问题的解决方案是类似于对象继承。如果你有“活动”正在发生的某些实体和要跟踪这些活动,然后参与几乎可以肯定的实体有共同之处。有你的基地台。从那里,你可以创建从底座表来跟踪特定于该亚型事情子表。例如,你可能有:
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),
)
如果您想为其所影响的对象类型,您可以添加一个类型代码为基础的活动,也可以直接确定由一个子表寻找存在。
下面是在大警告,虽然:确保对象/活动确实有一些共同点其中涉及他们需要你走这条路。你不想存储在同一个表脱节,不相关的数据。例如,你可以使用此方法来创建一个同时拥有银行账户的交易和天体事件的表,但是这不会是一个好主意。在基本水平,他们需要有共同的东西。
另外,我认为所有的活动都涉及到一个帐户,这就是为什么它在基表。任何在这些活动都进入基表。有关只有一个亚型事情的那些表所示。你甚至可以去多层次深,但不要得意忘形。这同样适用于物体(同样,糟糕的名字在这里,但我不知道你实际上处理)。如果你所有的物体有颜色,那么你可以把它放在桌子的对象。如果没有,那么它将进入子表。
其他提示
我要出去的肢体,并采取什么你真正想要实现一些乱撞。
你说你想跟踪“店活动”我要假设你有以下活动: 购买新项目 销售项目 核销项目 雇用员工 支付员工 消防员工 更新雇员记录
好了,对于这些活动,你需要几个不同的表格:一个用于库存,一个部门,一个是员工
在清单表可能具有以下信息:
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,或创建一个新的行,如果它是你从来没有过的项目。当你卖一个项目,你decriment的number_in_stock该项目(也因为当你注销的项目)。
当你雇用一名新员工,你从他们添加一条记录到员工表。当你付钱给他们,你抓住从工资列工资。当你解雇他们,你在那列他们的战绩填写(并停止支付他们)。
在所有这些中,操作不是由数据库来完成。 SQL应该用于跟踪的信息。它的优良写程序做这些更新(即从发票记录更新的所有项目一个新的发票程序)。但你并不需要一个表来的做的东西。事实上,一个表不能的做的东西。
在设计数据库,你要问的问题不是“什么,我需要做什么?”这是“我需要什么样的信息来跟踪?”
新的答案,根据问题的不同解释。
您只是想保持所发生的事情的清单?如果你只需要过去事件的有序列表,你只需要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”栏中的“添加新的行动。”
您可以更新创建行动,删除,添加等。
编辑: 我加入了action_details_or_description列事件。通过这种方式,你可以给有关的操作信息。例如,如果您有一个“产品改变颜色”的动作,说明可能是“红色”的新颜色。
更广泛地说,你要思考,并绘制出各种不同类型的,你将采取的提前行动,这样你就可以在能准确包含数据的方式建立你的表(S)要放入其中。
如何在SQL日志?
上次我需要数据库事务记录器时,我使用了 代替 数据库中的触发器,以便数据库不只是更新记录,而是将新记录插入日志表中。这种技术意味着我需要一个额外的表来保存数据库中每个表的日志,并且日志表有一个带有时间戳的附加列。如果需要,使用此技术您甚至可以存储记录的更新前和更新后状态。