我有一个 Java 程序来更新一个 SQL 表(id, name, status
)。使用相同的数据或一些更改的数据更新整个表。如何跟踪一行是否与更新前相同或是否有一些修改过的数据?id 将始终相同,只有名称上的小错字。如果名称被修改,我只想检查下一次更新。在这种情况下,状态字段应从“相同”更改为“已修改”。时间戳会解决我的问题吗?请帮忙。
4 回答
1 - 如果您要审核表(插入、更新、删除),请查看我的如何防止不需要的交易幻灯片和代码 - http://craftydba.com/?page_id=880。
见最后代码!
填充审计表的触发器可以保存来自多个表的信息,因为数据保存为 XML。因此,您可以在必要时取消删除。它跟踪谁和什么做出了改变。
2 - 如果您永远不会从审计表中清除数据,为什么不将该行标记为已删除,而是永远保留它?
许多系统,如 people soft 使用有效约会来显示记录是否不再有效。在 BI 世界中,这称为类型 2 维表(缓慢变化的维度)。
请参阅数据仓库研究所的文章。http://www.bidw.org/datawarehousing/scd-type-2/ 每条记录都有一个开始和结束日期。所有活动记录的结束日期均为空。
3 - Micorsoft SQL Server 引入了变更数据捕获功能。虽然这会在事后使用 LOG 阅读器跟踪数据更改,但它缺少诸如谁和什么进行了更改之类的信息。
同样,上述所有解决方案都有效。我偏爱我的解决方案!
真挚地
约翰
狡猾的 DBA
--
-- 7 - Auditing data changes (table for DML trigger)
--
-- Delete existing table
IF OBJECT_ID('[AUDIT].[LOG_TABLE_CHANGES]') IS NOT NULL
DROP TABLE [AUDIT].[LOG_TABLE_CHANGES]
GO
-- Add the table
CREATE TABLE [AUDIT].[LOG_TABLE_CHANGES]
(
[CHG_ID] [numeric](18, 0) IDENTITY(1,1) NOT NULL,
[CHG_DATE] [datetime] NOT NULL,
[CHG_TYPE] [varchar](20) NOT NULL,
[CHG_BY] [nvarchar](256) NOT NULL,
[APP_NAME] [nvarchar](128) NOT NULL,
[HOST_NAME] [nvarchar](128) NOT NULL,
[SCHEMA_NAME] [sysname] NOT NULL,
[OBJECT_NAME] [sysname] NOT NULL,
[XML_RECSET] [xml] NULL,
CONSTRAINT [PK_LTC_CHG_ID] PRIMARY KEY CLUSTERED ([CHG_ID] ASC)
) ON [PRIMARY]
GO
-- Add defaults for key information
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_DATE] DEFAULT (getdate()) FOR [CHG_DATE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_TYPE] DEFAULT ('') FOR [CHG_TYPE];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_CHG_BY] DEFAULT (coalesce(suser_sname(),'?')) FOR [CHG_BY];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_APP_NAME] DEFAULT (coalesce(app_name(),'?')) FOR [APP_NAME];
ALTER TABLE [AUDIT].[LOG_TABLE_CHANGES] ADD CONSTRAINT [DF_LTC_HOST_NAME] DEFAULT (coalesce(host_name(),'?')) FOR [HOST_NAME];
GO
--
-- 8 - Make DML trigger to capture changes
--
-- Delete existing trigger
IF OBJECT_ID('[ACTIVE].[TRG_FLUID_DATA]') IS NOT NULL
DROP TRIGGER [ACTIVE].[TRG_FLUID_DATA]
GO
-- Add trigger to log all changes
CREATE TRIGGER [ACTIVE].[TRG_FLUID_DATA] ON [ACTIVE].[CARS_BY_COUNTRY]
FOR INSERT, UPDATE, DELETE AS
BEGIN
-- Detect inserts
IF EXISTS (select * from inserted) AND NOT EXISTS (select * from deleted)
BEGIN
INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
SELECT 'INSERT', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM inserted as Record for xml auto, elements , root('RecordSet'), type)
RETURN;
END
-- Detect deletes
IF EXISTS (select * from deleted) AND NOT EXISTS (select * from inserted)
BEGIN
INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
SELECT 'DELETE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
RETURN;
END
-- Update inserts
IF EXISTS (select * from inserted) AND EXISTS (select * from deleted)
BEGIN
INSERT [AUDIT].[LOG_TABLE_CHANGES] ([CHG_TYPE], [SCHEMA_NAME], [OBJECT_NAME], [XML_RECSET])
SELECT 'UPDATE', '[ACTIVE]', '[CARS_BY_COUNTRY]', (SELECT * FROM deleted as Record for xml auto, elements , root('RecordSet'), type)
RETURN;
END
END;
GO
这取决于您需要多少信息。如果您只关心记录是否被修改过,您可以使用 created_when 和 updated_when 字段。如果后者大于前者,则已更新。
如果您想知道哪些字段已更新,则必须记录更改。细节取决于您的要求。如果您需要记录更改,触发器是最好的方法。
SQL Server 没有表级别的版本控制。如果要跟踪两个字段之间的差异,您至少有两个选项:
- 从您的 Java 应用程序控制 - 在您的更新方法中进行更新前检查。
- 来自 SQL Server 的控制 - 再次写入触发器以进行更新前检查
您还可以创建保留版本号的补充字段
是的,您可以使用时间戳。使用时间戳可以找出表中最新的条目,在查询中使用Order by timestamp可以得到最新的并根据对应的值设置状态