2017-04-05 49 views
0

在此项目中,每个表都有一个“历史表”,它与原始表相同,但添加了以下列:[HistId],[ActionUser],[ActionCode ],[ActionDate],[ValidUntil] 基本上每一个插入,更新,删除,我们就像一个日志。之后,我们很容易看到用户做了什么,谁做了什么,什么时候做了什么。仅在SQL表中显示已更改列的记录

看到它的外观,here

的问题是所显示的数据历史的方式。我发现它基本上是使用全选,并且所有内容都像Excel电子表格一样显示。 很难找到什么变化,什么不变。大多数情况下,这些更改一次只有一列。而当你试图找到具体的东西时,很难看到你需要的信息。

我想使用不同的方法。 我只想显示看起来像日志的内容所发生的变化。 (我也想使这个搜索以后)

它看起来喜欢的方式:

Record with title "a" inserted by albert on 2010-01-01 

Record's Title was updated from "a" to "b" by john on 2010-01-02 

Record's Title was updated from "b" to "c" by dave on 2010-01-03 

Record's Description was updated from "abc" to "def" by paul on 2010-01-04 

...etc... 

Record was deleted by bin on 2010-01-08 

因为我当时就想,要么1分的记录,这是6日的变化(标题和描述)或者2条记录,以较小者为准。 所以基本上我正在寻找一种方式,从一组记录只显示更改后的数据,没有别的

额外的信息:

  1. 历史表-S结构不能改变,因为有有很多像这样的表。

  2. 我想只改变我们检索数据的方式。

  3. 有20组以上的列

  4. 有30万条记录表的表,这样的表现是很重要的,但通常显示的数据过多也不会有,我会说50个记录最大值)

  5. 兼具“从”和“到”的每一行,看起来不错,但如果过于复杂,那么“到”足以

回答

1

假设 i)历史表不会因任何原因而改变。

ii)由于您一次将显示50,100,150条记录,因此不会出现问题。

试试这个,让我知道,

create table #side ([Id] [int] IDENTITY NOT NULL, 
       [Title] [varchar](50) NOT NULL, 
       [Description] [varchar](250) NULL) 

create table #h ([HistId] [int] IDENTITY(1,1) NOT NULL, 
       [Id] [int] NOT NULL, 
       [Title] [varchar](50) NOT NULL, 
       [Description] [varchar](250) NULL, 
       [TypeId] [int] NULL, 
       [ActionUser] [int] NULL, 
       [ActionCode] [char](1) NOT NULL, 
       [ActionDate] [datetime] NOT NULL, 
       [ValidUntil] [datetime] NULL) 

insert into #side ([Title],[Description]) values ('a','abc') 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'a','abc',123,991,'i','01/01/2010',NULL) 

declare @mod datetime; 
set @mod = '01/02/2010' 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'b','abc',123,991,'u',@mod,NULL) 


insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'c','abc',123,991,'u',@mod,NULL) 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'c','def',123,991,'u',@mod,NULL) 

insert into #h ([Id],[Title],[Description],[TypeId],[ActionUser],[ActionCode],[ActionDate],[ValidUntil]) values (1,'d','pqr',123,991,'u',@mod,NULL) 
select * from #h order by HistId Desc 
--select * from #side 

select h.HistId, case when h.ActionCode='i' THEN 
'Record with Title "'+h.title+'" inserted ' 
when h.ActionCode='u' THEN 
'Records '+ case 
when h.title<>h1.title and h.[Description]<>h1.[Description] then 'Title,Description was updated from 
"'+h1.title+'","'+h1.[Description]+'" to " '+h.title+' " , "'+h.[Description]+'" respectively' 
when h.title<>h1.title then 'Title was updated from "'+h1.title+'" to " '+h.title+' " ' 
when h.[Description]<>h1.[Description] then 'Description was updated from "'+h1.[Description]+'" to " '+h.[Description]+' " ' 
else '' end 
when h.ActionCode='d' THEN 
'Record was deleted' 
else 
null 
END 
+'by '+cast(h.ActionUser as varchar)+' on '+convert(varchar(10),h.actiondate ,120)+'' 
from #h h 
left join #h h1 
on h.HistId=(h1.HistId+1) 
--left join #usertable u 
--on u.userid=h.[ActionUser] 

drop table #h 
drop table #side 
0

这是一个简单的方法,即使用self-join比较每条记录与之前的条目。该技术假设HistId是一个不间断的整数序列。

样本数据

/* Sample data. 
* Three records are created. 
* The first is a base line. 
* The next two are updates. 
* Update one contains one change. 
* Update two contains two changes. 
* 
* See also: http://meta.stackoverflow.com/questions/333952/why-should-i-provide-an-mcve-for-what-seems-to-me-to-be-a-very-simple-sql-query 
*/ 
DECLARE @SampleHistory TABLE 
(
    HistoryId  INT IDENTITY(1, 1), 
    Title   VARCHAR(255), 
    [Description] VARCHAR(255) 
) 


INSERT INTO @SampleHistory 
(
    Title, 
    [Description] 
) 
VALUES 
    ('Data Warehouse Toolkit', 'First Edition'),   -- Base record. 
    ('Data Warehouse Toolkit', 'Second Edition'),   -- Description changed. 
    ('The Data Warehouse Toolkit', 'Third Edition')   -- Name and description changed. 
; 

查询

/* Change detection, using self join. 
* See also: https://msdn.microsoft.com/en-us/library/ms177490.aspx 
*/ 
SELECT 
    CASE 
     WHEN h2.Title IS NULL THEN 'New Title: ' + h1.Title + '. ' 
     WHEN h1.Title <> h2.Title THEN 'Title updated from ' + h2.Title + ' to ' + h1.Title + '. ' 
     ELSE '' 
    END 
    + 
    CASE 
     WHEN h2.[Description] IS NULL THEN 'New Description: ' + h1.[Description] + '. ' 
     WHEN h1.[Description] <> h2.Title THEN 'Description updated from ' + h2.[Description] + ' to ' + h1.[Description] + '. ' 
     ELSE '' 
    END 
FROM 
    @SampleHistory AS h1 
     LEFT OUTER JOIN @SampleHistory AS h2   ON h2.HistoryId = (h1.HistoryId - 1) 
; 

这样做的缺点的方法是你必须写在每一个历史表中每个字段的情况下表达。不好。避免所有这些类型的一种方法是使用dynamic SQL。但是这可能很复杂!

最后的思考

我不认为SQL是非常适合这样的任务。由于其基于集合的性质,循环遍历字段并有条件地返回值需要很多努力。在C#,Java等平台上,您可以获得相同的结果,并且花费更少的努力。

SQL Server 2016包括Change Data Capture开箱即用的所有版本。 CDC包含在SQL Server 2008,2012和2014 Enterprise和Developer版本中。在可能的情况;我更喜欢使用本机功能。手动解决方案需要管理,并且通常缺乏开发人员添加的高级功能。

相关问题