目标是存储插入,更新和删除业务记录等活动。
我正在考虑的一个解决方案是每个记录使用一个表进行跟踪。这是一个简化的例子:
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的情况下获取所有活动,但是对于获取所有活动然后尝试确定它们引用哪条记录似乎不太好。
也就是说,在此示例中,所有帐户名称和时间戳都存储在单独的表中,因此可以轻松创建专注于用户的报告,并专注于时间间隔,而无需了解特定活动的内容。 / p>
但是,如果您确实希望按类型报告活动,则此解决方案需要确定常规活动表所涉及的活动类型。
我可以将所有活动类型放在一个表中,但是ID不能被外键约束,而是表名可能被用作id,这将导致我使用动态查询。 / p>
在示例中请注意,DingBatActivity具有可选的按钮Id。如果在添加到dingbat后编辑了按钮名称,则活动将能够引用该按钮并知道其名称,因此如果报告按dingbat列出所有活动并按名称按按钮列出,则按钮名称将更改会自动反映在活动说明中。
寻找其他一些想法以及这些想法如何在编程工作,数据完整性,性能和报告灵活性之间妥协。
答案 0 :(得分:1)
我要走出困境,对你真正想要完成的事情进行一些猜测。
您说您正在尝试跟踪“商店活动”我将假设您有以下活动: 购买新商品 出售物品 注销项目 雇用员工 支付员工 消防员工 更新员工记录
好的,对于这些活动,您需要几个不同的表:一个用于库存,一个用于部门,一个用于员工
库存表可能包含以下信息:
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应该用于跟踪信息。编写执行这些更新的程序(一种更新发票记录中所有项目的新发票程序)是可以的。但是你不需要一个表来做的东西。实际上,表不能做任何事情。
在设计数据库时,您需要问的问题不是“我需要做什么?”它是“我需要跟踪哪些信息?”
答案 1 :(得分: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列添加到事件中。通过这种方式,您可以提供有关操作的更多信息。例如,如果您有“产品更改颜色”操作,则新颜色的描述可能为“红色”。
更广泛地说,您需要仔细考虑并绘制出您将提前采取的所有不同类型的操作,这样您就可以以能够准确包含数据的方式设置表格你想把它们放进去。
答案 2 :(得分:1)
我通常为这个问题设计解决方案的方式类似于对象中的继承。如果您对某些实体进行了“活动”,并且您想要跟踪这些活动,那么所涉及的实体几乎肯定会有一些共同点。有你的基表。从那里,您可以从基表创建子表,以跟踪特定于该子类型的内容。例如,您可能有:
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),
)
如果您想要对其影响的对象类型添加类型代码,或者您可以通过查找子表中的存在来确定该类型代码。
以下是大警告:确保对象/活动确实有一些与之相关的共同点,并要求您沿着这条路走下去。您不希望在同一个表中存储脱节的,不相关的数据。例如,您可以使用此方法创建一个包含银行帐户事务和天体事件的表,但这不是一个好主意。在基层,他们需要有一些共同点。
此外,我假设您的所有活动都与帐户相关,这就是它在基表中的原因。所有活动的共同点都在基表中。仅与子类型相关的事物会放在这些表格中。你甚至可以深入多层次,但不要被带走。对象也是如此(同样,这里的名字不好,但我不确定你实际处理的是什么)。如果所有对象都有颜色,则可以将其放在“对象”表中。如果没有,那么它将进入子表。
答案 3 :(得分:0)
SQL日志怎么样?
答案 4 :(得分:0)
我最后一次需要数据库事务记录器时,我在数据库中使用了Instead Of触发器,这样它就不会只更新记录,而是将新记录插入到日志表中。这种技术意味着我需要一个额外的表来保存数据库中每个表的日志,而日志表中还有一个带有时间戳的附加列。使用此技术,您甚至可以根据需要存储记录的更新前和更新后状态。